Experiment 1

Analysis of the Music data collected in September 2022

Following the preregistration: Larrouy-Maestri, P., & Wald-Fuhrmann, M. (2022, September 12). Definition of music: Effect of self- vs others-reference in the identification of auditory stimuli as music or not. Retrieved from osf.io/sb24q

Clear and load

install.packages("vcd")
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-x86_64/contrib/4.5/vcd_1.4-13.tgz'
Content type 'application/x-gzip' length 1304651 bytes (1.2 MB)
==================================================
downloaded 1.2 MB

The downloaded binary packages are in
    /var/folders/ry/qb5hyyns70q661g47x8kv7hx3txcp3/T//RtmpTf2wYm/downloaded_packages

Rescale the Confidence ratings(0-3 instead of 1-4) to match the intention and the methods

# Create a new column 'confidence_rescaled' that is a copy of 'Confidence'
Alldata$confidence_rescaled <- Alldata$Confidence

# Rescale 'confidence_rescaled' for all data
Alldata$confidence_rescaled<- Alldata$confidence_rescaled - 1

ANALYSIS 1: Effect of Condition (self versus other) on the categorisation of stimuli

Mixed effects logistic regression will be applied to predict the response (i.e., “Music” or “Not music”) from the condition, with random intercepts for participants and stimuli items.

NOTE that the syntax in the registration included the “a priori” condition but is not presented in the paper (only mentioned as a footnote) Proposed tentative syntax (in the registration): Music_answer ~ a priori group + Condition + a priori group:Condition + (1|Participant) + (1|Stim)

Code to change the baseline of the factors (self) for the model

Alldata$Condition <- as.factor(Alldata$Condition)
Alldata$Condition <- relevel(Alldata$Condition, ref = "self")

Null and simplest model, including only Condition:

Effect_null <- glmer(data = Alldata, Music_answer ~ 1 + (1|Participant) + (1|Stim), family = binomial)
summary(Effect_null)
Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) ['glmerMod']
 Family: binomial  ( logit )
Formula: Music_answer ~ 1 + (1 | Participant) + (1 | Stim)
   Data: Alldata

      AIC       BIC    logLik -2*log(L)  df.resid 
   8906.7    8930.1   -4450.4    8900.7     18081 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-40.002  -0.179   0.030   0.159  16.533 

Random effects:
 Groups      Name        Variance Std.Dev.
 Participant (Intercept)  0.9493  0.9743  
 Stim        (Intercept) 18.6233  4.3155  
Number of obs: 18084, groups:  Participant, 202; Stim, 90

Fixed effects:
            Estimate Std. Error z value Pr(>|z|)  
(Intercept)   0.8645     0.4658   1.856   0.0635 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Effect_log <- glmer(data = Alldata, Music_answer ~ Condition + (1|Participant) + (1|Stim), family = binomial)
summary(Effect_log)
Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) ['glmerMod']
 Family: binomial  ( logit )
Formula: Music_answer ~ Condition + (1 | Participant) + (1 | Stim)
   Data: Alldata

      AIC       BIC    logLik -2*log(L)  df.resid 
   8903.1    8934.3   -4447.6    8895.1     18080 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-39.331  -0.177   0.031   0.161  16.680 

Random effects:
 Groups      Name        Variance Std.Dev.
 Participant (Intercept)  0.9208  0.9596  
 Stim        (Intercept) 18.6715  4.3211  
Number of obs: 18084, groups:  Participant, 202; Stim, 90

Fixed effects:
               Estimate Std. Error z value Pr(>|z|)  
(Intercept)      1.0413     0.4715   2.209   0.0272 *
Conditionother  -0.3488     0.1464  -2.383   0.0172 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
            (Intr)
Conditinthr -0.154
anova(Effect_null,Effect_log)
Data: Alldata
Models:
Effect_null: Music_answer ~ 1 + (1 | Participant) + (1 | Stim)
Effect_log: Music_answer ~ Condition + (1 | Participant) + (1 | Stim)
            npar    AIC    BIC  logLik -2*log(L)  Chisq Df Pr(>Chisq)  
Effect_null    3 8906.7 8930.1 -4450.4    8900.7                       
Effect_log     4 8903.1 8934.3 -4447.6    8895.1 5.5878  1    0.01809 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Details about the full model

tidy (Effect_log)
performance(Effect_log)
# Indices of model performance

AIC      |     AICc |      BIC | R2 (cond.) | R2 (marg.) |   ICC |  RMSE | Sigma | Log_loss | Score_log | Score_spherical
-------------------------------------------------------------------------------------------------------------------------
8903.136 | 8903.138 | 8934.347 |      0.856 |      0.001 | 0.856 | 0.257 | 1.000 |    0.217 |      -Inf |       2.285e-04

ICC for the random effects (all together and separately)

# ICC calculation by group
icc_results_group <- performance::icc(Effect_log, by_group = TRUE)
print(icc_results_group)
# ICC by Group

Group       |   ICC
-------------------
Participant | 0.040
Stim        | 0.816
# ICC calculation for all random
icc_results_all <- performance::icc(Effect_log, by_group = FALSE)
print(icc_results_all)
# Intraclass Correlation Coefficient

    Adjusted ICC: 0.856
  Unadjusted ICC: 0.855

ANALYSIS 1bis: Effect of condition (Condition: self versus other) on the confidence ratings (confidence as ordinal variable)

conf_ord_r <- mutate(Alldata, confidence_rescaled = factor(confidence_rescaled, levels=0:3, ordered=TRUE))
conf_ord_r <- mutate(Alldata, Condition = factor(Condition, ordered=FALSE))

# Check the class and levels of the 'Confidence' variable
class(conf_ord_r$confidence_rescaled)
[1] "numeric"
levels(conf_ord_r$confidence_rescaled)
NULL
# Convert 'Confidence' to factor if it's not already
conf_ord_r$confidence_rescaled <- factor(conf_ord_r$confidence_rescaled, ordered = TRUE)

# Check the class and levels again
class(conf_ord_r$confidence_rescaled)
[1] "ordered" "factor" 
levels(conf_ord_r$confidence_rescaled)
[1] "0" "1" "2" "3"
# Fit the CLMM model without the effect of Condition
Effect_Conf_null_r <- clmm(confidence_rescaled ~ 1 + (1|Participant) + (1|Stim), data = conf_ord_r, link = "probit", threshold = "equidistant")
summary(Effect_Conf_null_r)
Cumulative Link Mixed Model fitted with the Laplace approximation

formula: confidence_rescaled ~ 1 + (1 | Participant) + (1 | Stim)
data:    conf_ord_r

Random effects:
 Groups      Name        Variance Std.Dev.
 Participant (Intercept) 0.2899   0.5384  
 Stim        (Intercept) 0.7301   0.8545  
Number of groups:  Participant 202,  Stim 90 

No Coefficients

Threshold coefficients:
            Estimate Std. Error z value
threshold.1 -2.59734    0.10010  -25.95
spacing      1.13614    0.01139   99.77
# Fit the CLMM model with the effect of Condition
model_conf_ord_r <- clmm(confidence_rescaled ~ Condition + (1 | Participant) + (1 | Stim), data = conf_ord_r, link = "probit", threshold = "equidistant")
summary(model_conf_ord_r)
Cumulative Link Mixed Model fitted with the Laplace approximation

formula: confidence_rescaled ~ Condition + (1 | Participant) + (1 | Stim)
data:    conf_ord_r

Random effects:
 Groups      Name        Variance Std.Dev.
 Participant (Intercept) 0.2894   0.5379  
 Stim        (Intercept) 0.7301   0.8544  
Number of groups:  Participant 202,  Stim 90 

Coefficients:
               Estimate Std. Error z value Pr(>|z|)
Conditionother -0.04595    0.07816  -0.588    0.557

Threshold coefficients:
            Estimate Std. Error z value
threshold.1 -2.62030    0.10746  -24.38
spacing      1.13614    0.01139   99.77
# Comparison of the null and full model for confidence
anova(Effect_Conf_null_r,model_conf_ord_r)
Likelihood ratio tests of cumulative link models:
 

                   no.par   AIC logLik LR.stat df Pr(>Chisq)
Effect_Conf_null_r      4 29849 -14921                      
model_conf_ord_r        5 29851 -14920  0.3454  1     0.5568
# ICC calculation by group (i.e., each random effects) for the NULL model (since the full model is not better)
icc_results_group <- performance::icc(Effect_Conf_null_r, by_group = TRUE)
print(icc_results_group)
# ICC by Group

Group       |   ICC
-------------------
Participant | 0.144
Stim        | 0.361
# ICC calculation for all random effects together for the NULL model (since the full model is not better)
icc_results_all <- performance::icc(Effect_Conf_null_r, by_group = FALSE)
print(icc_results_all)
# Intraclass Correlation Coefficient

    Adjusted ICC: 0.505
  Unadjusted ICC: 0.505

Figure 1A

# Compute mean music responses and mean confidence ratings
DataPlot <- with(Alldata, aggregate(cbind(Music_answer, confidence_rescaled), list(Stimuli=Stim, Condition = Condition), mean))
DataPlot

Setting colors for the plots


self = "orange"
other = "purple"

Condition_colors = c(self,other)

Plotting the music answers with 2 contrasted colors (Conditions: 1st and 3rd person, also names Self and Other conditions), with order according to the Self values

# Calculate the mean Music_answer for each stimulus in the "self" condition
self_means <- with(subset(Alldata, Condition == "self"), 
                   tapply(Music_answer, Stim, mean, na.rm = TRUE))

# Ensure the Music_answer column is numeric
DataPlot$Music_answer <- as.numeric(DataPlot$Music_answer)

# Reorder the Stimuli factor levels based on the means in the "self" condition
DataPlot$Stimuli <- factor(DataPlot$Stimuli, 
                           levels = names(sort(self_means, decreasing = FALSE)))

# Reorder the levels of the Condition factor
DataPlot$Condition <- factor(DataPlot$Condition, levels = c("self", "other"))

ResponsePlot <- ggplot(DataPlot, aes(x = reorder(Stimuli, Music_answer), y = Music_answer, group = Condition, colour = Condition)) +
  geom_point(aes(shape = Condition), size = 3.5) +
  scale_colour_manual(values = Condition_colors, 
                      labels = c("1st person", "3rd person")) +  # Rename Condition labels
  scale_shape_manual(values = c("self" = 16,   # Solid circle
                                "other" = 1),   # Hollow circle
                     labels = c("1st person", "3rd person")) +
  theme_classic() +
  xlab("Stimuli (n = 90)") +
  ylab("Music responses") +
  theme(axis.text.x = element_blank(),
        legend.text = element_text(size = 10),
        legend.title = element_text(size = 10),
        legend.position = c(0.8, 0.4),
        axis.title.y = element_text(size = 14),
        axis.title.x = element_text(size = 12),
        panel.background = element_rect(fill = "white"))  # Ensure white background

ResponsePlot

Plotting Confidence for self and other conditions

# Reorder the Stimuli factor levels based on the means in the "self" condition
DataPlot$Stimuli <- factor(DataPlot$Stimuli, 
                           levels = names(sort(self_means, decreasing = FALSE)))

# Reorder the levels of the Condition factor
DataPlot$Condition <- factor(DataPlot$Condition, levels = c("self", "other"))

ResponsePlot_conf <- ggplot(DataPlot, aes(x = reorder(Stimuli, Music_answer), y = confidence_rescaled, group = Condition, colour = Condition)) +
  geom_point(aes(shape = Condition), size = 3.5) +  # Adjust size for circles
  scale_colour_manual(values = Condition_colors, 
                      labels = c("1st person", "3rd person")) +  # Rename Condition labels
  scale_shape_manual(values = c("self" = 16,   # Solid circle for "self"
                                "other" = 1),   # Hollow circle for "other"
                     labels = c("1st person", "3rd person")) +
  theme_classic() +
  xlab("Stimuli (n = 90)") +
  ylab("Confidence") +
  ylim(1.3, 3) +  # Adjust y-axis limits as needed
  theme(axis.text.x = element_blank(), 
        legend.text = element_text(size = 12), # Change legend text font size
        legend.title = element_text(size = 12), # Change legend title font size
        legend.position = "none",  # Remove the legend
        axis.title.y = element_text(size = 14),
        axis.title.x = element_text(size = 12)) +
  theme(panel.background = element_rect(fill = "white"))

ResponsePlot_conf

NA
NA

Combine plots Identification/Confidence and save


Figure_1 <- grid.arrange(ResponsePlot,ResponsePlot_conf,ncol = 1)

ggsave("~/Desktop/ResponsePlot_exp1.tiff", plot = Figure_1, width = 5, height = 5, dpi = 600, device = "tiff", compression = "lzw")

Experiment 2

Analysis of the Music data collected in November 2022

Following the preregistration: Larrouy-Maestri, P., & Wald-Fuhrmann, M. (2022, November 21). Perception of sounds as music or not: effect of stimulus duration Retrieved from osf.io/azkcp

Clear and load

rm(list = ls())

# Set working directory
setwd("/Users/p.larrouy/Desktop/Music_osf")
Error in setwd("/Users/p.larrouy/Desktop/Music_osf") : 
  cannot change working directory

Rescale the Confidence ratings for duration short and long (0-3 instead of 1-4) to match the intention, the methods, and the date of the medium duration (i.e., data of Exp1, self)

# Create a new column 'confidence_rescaled' that is a copy of 'confidence'
Alldata$confidence_rescaled <- Alldata$confidence

# Rescale 'confidence_rescaled' for Duration values 2 and 9
Alldata$confidence_rescaled[Alldata$Duration_label %in% c("short", "long")] <- Alldata$confidence_rescaled[Alldata$Duration_label %in% c("short", "long")] - 1

# Optional: Verify the changes
# You can check a subset of the data to ensure the changes are correct
head(Alldata[Alldata$Duration_label %in% c("short", "long"), c("Duration_label", "confidence", "confidence_rescaled")])
NA

ANALYSIS 1: Effect of duration (2 versus 5 versus 10) on the categorisation of stimuli

Mixed effects logistic regression will be applied to predict the response (i.e., “Music” or “Not music”) from the condition (i.e., duration: 2, 5, 10 seconds), with random intercepts for participants and stimuli items.

NOTE that we don’t use the results of Exp1 (3 groups:music, no_music, ambiguous) since we reuse the data of the “self” group from which the three groups were defined

NOTE that the syntax in the registration included the “a priori” condition but is not presented in the paper (only mentioned as a footnote) Proposed tentative syntax (in the registration): Music_answer ~ a priori group + Duration + a priori group:Duration + (1|exp_subject_id) + (1|stim_name)

Code to change the baseline of the factors (Duration_label) for the model

Alldata$Duration_label <- as.factor(Alldata$Duration_label)
Alldata$Duration_label <- relevel(Alldata$Duration_label, ref = "medium")

Null and simplest model, including only duration:

Effect_null <- glmer(data = Alldata, Music_answer ~ 1 + (1|exp_subject_id) + (1|stim_name), family = binomial)
summary(Effect_null)
Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) ['glmerMod']
 Family: binomial  ( logit )
Formula: Music_answer ~ 1 + (1 | exp_subject_id) + (1 | stim_name)
   Data: Alldata

      AIC       BIC    logLik -2*log(L)  df.resid 
    11002     11026     -5498     10996     22347 

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-18.4936  -0.1994   0.0281   0.1433  19.6758 

Random effects:
 Groups         Name        Variance Std.Dev.
 exp_subject_id (Intercept)  0.9988  0.9994  
 stim_name      (Intercept) 20.2061  4.4951  
Number of obs: 22350, groups:  exp_subject_id, 298; stim_name, 75

Fixed effects:
            Estimate Std. Error z value Pr(>|z|)   
(Intercept)   1.6566     0.5289   3.132  0.00174 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Effect_log <- glmer(data = Alldata, Music_answer ~ Duration_label + (1|exp_subject_id) + (1|stim_name), family = binomial)
summary(Effect_log)
Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) ['glmerMod']
 Family: binomial  ( logit )
Formula: Music_answer ~ Duration_label + (1 | exp_subject_id) + (1 | stim_name)
   Data: Alldata

      AIC       BIC    logLik -2*log(L)  df.resid 
  10993.3   11033.3   -5491.6   10983.3     22345 

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-18.1067  -0.1984   0.0287   0.1436  20.0522 

Random effects:
 Groups         Name        Variance Std.Dev.
 exp_subject_id (Intercept)  0.9486  0.9739  
 stim_name      (Intercept) 20.1970  4.4941  
Number of obs: 22350, groups:  exp_subject_id, 298; stim_name, 75

Fixed effects:
                    Estimate Std. Error z value Pr(>|z|)    
(Intercept)           1.9430     0.5345   3.635 0.000278 ***
Duration_labellong   -0.3282     0.1509  -2.175 0.029660 *  
Duration_labelshort  -0.5396     0.1508  -3.579 0.000345 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
            (Intr) Drtn_lbll
Drtn_lbllng -0.139          
Drtn_lblshr -0.139  0.493   
anova(Effect_null,Effect_log)
Data: Alldata
Models:
Effect_null: Music_answer ~ 1 + (1 | exp_subject_id) + (1 | stim_name)
Effect_log: Music_answer ~ Duration_label + (1 | exp_subject_id) + (1 | stim_name)
            npar   AIC   BIC  logLik -2*log(L)  Chisq Df Pr(>Chisq)   
Effect_null    3 11002 11026 -5498.0     10996                        
Effect_log     5 10993 11033 -5491.6     10983 12.697  2    0.00175 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Details about the full model

tidy (Effect_log)
performance(Effect_log)
# Indices of model performance

AIC       |      AICc |       BIC | R2 (cond.) | R2 (marg.) |   ICC |  RMSE | Sigma | Log_loss | Score_log | Score_spherical
----------------------------------------------------------------------------------------------------------------------------
10993.270 | 10993.273 | 11033.343 |      0.866 |      0.002 | 0.865 | 0.259 | 1.000 |    0.219 |      -Inf |       6.644e-05

ICC for the random effects (all together and separately)

# ICC calculation by group
icc_results_group <- performance::icc(Effect_log, by_group = TRUE)
print(icc_results_group)
# ICC by Group

Group          |   ICC
----------------------
exp_subject_id | 0.039
stim_name      | 0.827
# ICC calculation for all random
icc_results_all <- performance::icc(Effect_log, by_group = FALSE)
print(icc_results_all)
# Intraclass Correlation Coefficient

    Adjusted ICC: 0.865
  Unadjusted ICC: 0.864

ANALYSIS 1bis: Effect of condition (duration: short, medium, long) on the confidence ratings (confidence as ordinal variable)

conf_ord_r <- mutate(Alldata, confidence_rescaled = factor(confidence_rescaled, levels=0:3, ordered=TRUE))
conf_ord_r <- mutate(Alldata, Condition = factor(Duration_label, ordered=FALSE))

# Check the class and levels of the 'Confidence' variable
class(conf_ord_r$confidence_rescaled)
[1] "numeric"
levels(conf_ord_r$confidence_rescaled)
NULL
# Convert 'Confidence' to factor if it's not already
conf_ord_r$confidence_rescaled <- factor(conf_ord_r$confidence_rescaled, ordered = TRUE)

# Check the class and levels again
class(conf_ord_r$confidence_rescaled)
[1] "ordered" "factor" 
levels(conf_ord_r$confidence_rescaled)
[1] "0" "1" "2" "3"
# Fit the CLMM model without the effect of Condition
Effect_Conf_null_r <- clmm(confidence_rescaled ~ 1 + (1|exp_subject_id) + (1|stim_name), data = conf_ord_r, link = "probit", threshold = "equidistant")
summary(Effect_Conf_null_r)
Cumulative Link Mixed Model fitted with the Laplace approximation

formula: confidence_rescaled ~ 1 + (1 | exp_subject_id) + (1 | stim_name)
data:    conf_ord_r

Random effects:
 Groups         Name        Variance Std.Dev.
 exp_subject_id (Intercept) 0.3114   0.558   
 stim_name      (Intercept) 0.7465   0.864   
Number of groups:  exp_subject_id 298,  stim_name 75 

No Coefficients

Threshold coefficients:
            Estimate Std. Error z value
threshold.1 -2.56205    0.10664  -24.02
spacing      1.11763    0.01006  111.13
# Fit the CLMM model with the effect of Condition
model_conf_ord_r <- clmm(confidence_rescaled ~ Duration_label + (1 | exp_subject_id) + (1 | stim_name), data = conf_ord_r, link = "probit", threshold = "equidistant")
summary(model_conf_ord_r)
Cumulative Link Mixed Model fitted with the Laplace approximation

formula: confidence_rescaled ~ Duration_label + (1 | exp_subject_id) +      (1 | stim_name)
data:    conf_ord_r

Random effects:
 Groups         Name        Variance Std.Dev.
 exp_subject_id (Intercept) 0.3104   0.5572  
 stim_name      (Intercept) 0.7465   0.8640  
Number of groups:  exp_subject_id 298,  stim_name 75 

Coefficients:
                    Estimate Std. Error z value Pr(>|z|)
Duration_labellong   0.01056    0.08187   0.129    0.897
Duration_labelshort -0.05704    0.08164  -0.699    0.485

Threshold coefficients:
            Estimate Std. Error z value
threshold.1 -2.57749    0.11639  -22.14
spacing      1.11763    0.01006  111.13
# Comparison of the null and full model for confidence
anova(Effect_Conf_null_r,model_conf_ord_r)
Likelihood ratio tests of cumulative link models:
 

                   no.par   AIC logLik LR.stat df Pr(>Chisq)
Effect_Conf_null_r      4 37154 -18573                      
model_conf_ord_r        6 37157 -18573  0.7844  2     0.6756
# ICC calculation by group (i.e., each random effects) for the NULL model (since the full model is not better)
icc_results_group <- performance::icc(Effect_Conf_null_r, by_group = TRUE)
print(icc_results_group)
# ICC by Group

Group          |   ICC
----------------------
exp_subject_id | 0.151
stim_name      | 0.363
# ICC calculation for all random effects together for the NULL model (since the full model is not better)
icc_results_all <- performance::icc(Effect_Conf_null_r, by_group = FALSE)
print(icc_results_all)
# Intraclass Correlation Coefficient

    Adjusted ICC: 0.514
  Unadjusted ICC: 0.514

Figure 1B

# Compute mean music responses and mean confidence ratings
DataPlot <- with(Alldata, aggregate(Music_answer, list(Stimuli=stim_name,Condition=Duration_label), mean))

Setting colors for the plots

s = "gold"
m = "orange"
l = "brown"

dur_colors = c(s,m,l)

Plotting the music answers with 3 colors (Conditions: Short, Medium, and Long stimuli)

DataPlot <- with(Alldata, aggregate(Music_answer, list(Stimuli=stim_name,Condition=Duration_label), mean))

# Reorder the levels of the Condition factor
DataPlot$Condition <- factor(DataPlot$Condition, levels = c("short", "medium", "long"))

# Create the plot with the reordered Condition levels
ResponsePlot <- ggplot(DataPlot, aes(x = reorder(Stimuli, x), y = x, group = Condition, colour = Condition)) +
  geom_point(aes(shape = Condition), size = 3.5) +
  scale_colour_manual(values = dur_colors,
                      labels = c("Short", "Medium", "Long")) +
  scale_shape_manual(values = c("short" = 1,   # Solid circle
                                 "medium" = 16,
                                 "long"= 1),   # Hollow circle
                     labels = c("Short", "Medium", "Long")) +
  theme_classic() +
  xlab("Stimuli (n = 75)") +
  ylab("Music responses") +
  theme(axis.text.x = element_blank(), 
        legend.text = element_text(size = 10), 
        legend.title = element_text(size = 10), 
        legend.position = c(0.8, 0.4),
        axis.title.y = element_text(size = 14),
        axis.title.x = element_text(size = 12)) +
  theme(panel.background = element_rect(fill = "white"))

ResponsePlot

Plotting Confidence for Short, Medium, and Long stimuli

# Compute mean music responses and mean confidence ratings
DataPlot <- with(Alldata, aggregate(cbind(Music_answer, confidence_rescaled), list(Stimuli=stim_name, Condition = Duration_label), mean))
DataPlot

# Reorder the levels of the Condition factor
DataPlot$Condition <- factor(DataPlot$Condition, levels = c("short", "medium", "long"))

# Plot confidence like for identification
ResponsePlot_conf <- ggplot(DataPlot, aes(x = reorder(Stimuli, Music_answer), y = confidence_rescaled, group = Condition, colour = Condition)) +
  geom_point(aes(shape = Condition), size = 3.5) +
  scale_colour_manual(values = dur_colors,
                      labels = c("Short", "Medium", "Long")) +
  scale_shape_manual(values = c("short" = 1,   # Hollow circle
                                 "medium" = 16, # Solid circle
                                 "long"= 1),   # Hollow circle
                     labels = c("Short", "Medium", "Long")) +
  theme_classic() +
  # scale_shape(solid = FALSE) +
  xlab("Stimuli (n = 75)") +
  ylab("Confidence") +
  ylim(1.3, 3) +  # Adjust y-axis limits as needed
  theme(axis.text.x = element_blank(), 
        legend.text = element_text(size = 12), # Change legend text font size
        legend.title = element_text(size = 12), # Change legend title font size
        legend.position = "none",  # Remove the legend
        axis.title.y = element_text(size = 14),
        axis.title.x = element_text(size = 12)) +
  theme(panel.background = element_rect(fill = "white"))

ResponsePlot_conf

Combine plots and save


Figure_1B <- grid.arrange(ResponsePlot,ResponsePlot_conf,ncol = 1)

ggsave("~/Desktop/ResponsePlot_exp2.tiff", plot = Figure_1B, width = 4, height = 5, dpi = 600, device = "tiff", compression = "lzw")

Experiment 3

Analysis of the Music data collected in November 2022

Following the preregistration: Larrouy-Maestri, P., & Wald-Fuhrmann, M. (2022, November 21). Perception of sounds as music or not: effect of stimulus duration Retrieved from osf.io/azkcp

Clear and load

rm(list = ls())

# Set working directory
setwd("/Users/p.larrouy/Desktop/Music_osf")
Error in setwd("/Users/p.larrouy/Desktop/Music_osf") : 
  cannot change working directory

ANALYSIS 1: Effect of repetition on the categorisation of stimuli

Mixed effects logistic regression will be applied to predict the response (i.e., “Music” or “Not music”) from the condition (i.e., first or second presentation), with random intercepts for participants and stimuli items.

NOTE that the syntax in the registration included the “a priori” condition but is not presented in the paper (only mentioned as a footnote) Proposed tentative syntax (in the registration): Music_answer ~ a priori group + Order + a priori group:Order + (1|exp_subject_id) + (1|stim_name)

Code to change the baseline of the factors (Order_letter) for the model

Alldata$Order_letter <- as.factor(Alldata$Order_letter)
Alldata$Order_letter <- relevel(Alldata$Order_letter, ref = "test")

Null and simplest model, including only duration:

Effect_null <- glmer(data = Alldata, Music_answer ~ 1 + (1|exp_subject_id) + (1|stim_name), family = binomial)
summary(Effect_null)
Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) ['glmerMod']
 Family: binomial  ( logit )
Formula: Music_answer ~ 1 + (1 | exp_subject_id) + (1 | stim_name)
   Data: Alldata

      AIC       BIC    logLik -2*log(L)  df.resid 
  11160.6   11184.4   -5577.3   11154.6     20157 

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-15.2054  -0.2813  -0.0531   0.1321  20.0969 

Random effects:
 Groups         Name        Variance Std.Dev.
 exp_subject_id (Intercept)  1.93    1.389   
 stim_name      (Intercept) 14.75    3.841   
Number of obs: 20160, groups:  exp_subject_id, 240; stim_name, 42

Fixed effects:
            Estimate Std. Error z value Pr(>|z|)
(Intercept)  -0.6018     0.5992  -1.004    0.315
Effect_log <- glmer(data = Alldata, Music_answer ~ Order_letter + (1|exp_subject_id) + (1|stim_name), family = binomial)
summary(Effect_log)
Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) ['glmerMod']
 Family: binomial  ( logit )
Formula: Music_answer ~ Order_letter + (1 | exp_subject_id) + (1 | stim_name)
   Data: Alldata

      AIC       BIC    logLik -2*log(L)  df.resid 
  11158.7   11190.3   -5575.3   11150.7     20156 

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-15.6036  -0.2817  -0.0522   0.1324  20.6263 

Random effects:
 Groups         Name        Variance Std.Dev.
 exp_subject_id (Intercept)  1.932   1.390   
 stim_name      (Intercept) 14.761   3.842   
Number of obs: 20160, groups:  exp_subject_id, 240; stim_name, 42

Fixed effects:
                   Estimate Std. Error z value Pr(>|z|)  
(Intercept)        -0.55223    0.60260  -0.916   0.3594  
Order_letterretest -0.09978    0.04960  -2.012   0.0443 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
            (Intr)
Ordr_lttrrt -0.041
anova(Effect_null,Effect_log)
Data: Alldata
Models:
Effect_null: Music_answer ~ 1 + (1 | exp_subject_id) + (1 | stim_name)
Effect_log: Music_answer ~ Order_letter + (1 | exp_subject_id) + (1 | stim_name)
            npar   AIC   BIC  logLik -2*log(L)  Chisq Df Pr(>Chisq)  
Effect_null    3 11161 11184 -5577.3     11155                       
Effect_log     4 11159 11190 -5575.3     11151 3.9429  1    0.04707 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Details about the full model

tidy (Effect_log)
performance(Effect_log)
# Indices of model performance

AIC       |      AICc |       BIC | R2 (cond.) | R2 (marg.) |   ICC |  RMSE | Sigma | Log_loss | Score_log | Score_spherical
----------------------------------------------------------------------------------------------------------------------------
11158.680 | 11158.682 | 11190.325 |      0.835 |  1.245e-04 | 0.835 | 0.277 | 1.000 |    0.249 |      -Inf |       5.847e-04

ICC for the random effects (all together and separately)

# ICC calculation by group
icc_results_group <- performance::icc(Effect_log, by_group = TRUE)
print(icc_results_group)
# ICC by Group

Group          |   ICC
----------------------
exp_subject_id | 0.097
stim_name      | 0.739
# ICC calculation for all random
icc_results_all <- performance::icc(Effect_log, by_group = FALSE)
print(icc_results_all)
# Intraclass Correlation Coefficient

    Adjusted ICC: 0.835
  Unadjusted ICC: 0.835

Figure 1C

Preparation for the figure with each retests (3 conditions) against the baseline (single for all “test”)


Alldata <- Alldata %>%
  mutate(New_Group = case_when(
    Order_letter == 'test'  ~ 'Baseline',
    Order_letter == 'retest' & Position == 'BB' ~ 'BB',
    Order_letter == 'retest' & Position == 'WBR' ~ 'WBR',
    Order_letter == 'retest' & Position == 'WBC' ~ 'WBC',
    TRUE ~ 'Other'
  ))

Setting colors for the plots

baseline = "grey"
BB = "pink"
WBR = "cyan"
WBC = "magenta"

Position_colors = c(baseline,BB,WBR,WBC)

Plotting the music answers with 3 colors (Conditions: Baseline, BB, WBC, WBR)


## From exp2:
  # Compute mean music responses and mean confidence ratings
DataPlot <- with(Alldata, aggregate(Music_answer, list(Stimuli=stim_name,Condition=New_Group), mean))

DataPlot

Baseline_means <- with(subset(Alldata, New_Group == "Baseline"), 
                   tapply(Music_answer, stim_name, mean, na.rm = TRUE))

# Reorder the Stimuli factor levels based on the means in the "self" condition
DataPlot$Stimuli <- factor(DataPlot$Stimuli, 
                           levels = names(sort(Baseline_means, decreasing = FALSE)))

# Reorder the levels of the Condition factor
DataPlot$Condition <- factor(DataPlot$Condition, levels = c("Baseline", "BB", "WBR","WBC"))


# Create the plot with the reordered Condition levels
ResponsePlot <- ggplot(DataPlot, aes(Stimuli, y = x, group = Condition, colour = Condition)) +
  geom_point(aes(shape = Condition), size = 3.5) +
  scale_colour_manual(values = Position_colors,
                      labels = c("Baseline",  "BB", "WBR","WBC")) +
  scale_shape_manual(values = c("Baseline" = 16,   # Solid circle
                                 "BB" = 1,
                                 "WBR"= 1,
                                 "WBC"= 1),   # Hollow circle
                     labels = c("Baseline",  "BB", "WBR","WBC")) +
  theme_classic() +
  xlab("Stimuli (n = 42)") +
  ylab("Music responses") +
  theme(axis.text.x = element_blank(), 
        legend.text = element_text(size = 12), 
        legend.title = element_text(size = 12), 
        legend.position = c(0.25, 0.7),  # Move legend to top-left
        axis.title.y = element_text(size = 14),
        axis.title.x = element_text(size = 12),
        legend.spacing.y = unit(0.1, "cm")) +  # Adjust space between legend items
  theme(panel.background = element_rect(fill = "white"))
ResponsePlot

Create and export plot

Figure_1C <- grid.arrange(ResponsePlot,ncol = 1)

ggsave("~/Desktop/ResponsePlot_exp3a.tiff", plot = Figure_1C, width = 3, height = 2, dpi = 600, device = "tiff", compression = "lzw")

Listeners’ consistence observed with test-retest phi-coefficients for each condition

consist_sub <- with(Alldata, aggregate(Music_answer, list(Sub=exp_subject_id, Stimuli=stim_name,Position=Position,Repetition=Order), mean))
consist_sub

consistency_sub <-reshape(consist_sub, idvar =c("Stimuli", "Position","Sub"), timevar = c("Repetition"), direction = "wide")
consistency_sub 

sub_correlation <- consistency_sub %>%
  group_by(Sub, Position) %>%
  summarise(
    phi_coefficient = {
      tbl <- table(x.1, x.2)
      assocstats(tbl)$phi
    },
    p_value = {
      tbl <- table(x.1, x.2)
      chisq.test(tbl)$p.value
    }
  )

print(sub_correlation)

Plot listeners’ consistency between first and second presentation (grey dot for each stimulus on a x axis) for each Position separately (y axis)

# Plot the difference values for each group in 'Position'

# Function to calculate mean and confidence intervals
mean_ci <- function(x) {
  mean_x <- mean(x)
  ci <- qt(0.975, df = length(x) - 1) * sd(x) / sqrt(length(x))
  return(data.frame(y = mean_x, ymin = mean_x - ci, ymax = mean_x + ci))
}

Position_colors_violin = c(BB,WBC,WBR)

# Plot itself
ConsistencyPlot <- ggplot(sub_correlation, aes(x = Position, y = phi_coefficient, colour = Position, fill = Position)) +
  #geom_violin(alpha = 0.5) +
  geom_boxplot(alpha = 0.5)+
  scale_colour_manual(values = Position_colors_violin) +
  scale_fill_manual(values = Position_colors_violin) +
  geom_jitter(width = 0.2, alpha = 0.5) +
  stat_summary(fun.data = mean_ci, geom = "pointrange", color = "black", size = 0.5) +
  theme_classic() +
  labs(#title = "Exp 3",
       x = "Position",
       y = "Phi coeficient") +
  theme(legend.position="Position",
        axis.title.y = element_text(size = 14),
        axis.title.x = element_text(size = 12)) +
  theme(panel.background = element_rect(fill = "white"))

ConsistencyPlot

Creation and export of figure 1C

Figure_1C <- grid.arrange(ResponsePlot,ConsistencyPlot,ncol = 1)

ggsave("~/Desktop/ResponsePlot_exp3.tiff", plot = Figure_1C, width = 3, height = 5, dpi = 600, device = "tiff", compression = "lzw")

Comparison of listeners’ consistency (i.e., Phi coefficients) across conditions with anova and Turkey test

## Test the effect of Position on the Phi coefficients with (independent measures) Anova
consistency_anova <- aov(phi_coefficient~factor(Position), data = sub_correlation)
summary(consistency_anova)
                  Df Sum Sq Mean Sq F value   Pr(>F)    
factor(Position)   2 0.9032  0.4516   40.46 7.65e-16 ***
Residuals        237 2.6454  0.0112                     
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Run the ANOVA
consistency_anova <- aov(phi_coefficient ~ factor(Position), data = sub_correlation)
summary(consistency_anova)
                  Df Sum Sq Mean Sq F value   Pr(>F)    
factor(Position)   2 0.9032  0.4516   40.46 7.65e-16 ***
Residuals        237 2.6454  0.0112                     
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Perform Tukey HSD post hoc test
tukey_result <- TukeyHSD(consistency_anova)

# Display the Tukey HSD result
print(tukey_result)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = phi_coefficient ~ factor(Position), data = sub_correlation)

$`factor(Position)`
              diff         lwr         upr     p adj
WBC-BB   0.1355419  0.09626492  0.17481894 0.0000000
WBR-BB   0.0117657 -0.02763617  0.05116758 0.7611985
WBR-WBC -0.1237762 -0.16329951 -0.08425295 0.0000000
# Calculate mean and standard deviation of phi_coefficient per Position
summary_stats <- sub_correlation %>%
  group_by(Position) %>%
  summarise(
    mean_phi = mean(phi_coefficient, na.rm = TRUE),
    sd_phi = sd(phi_coefficient, na.rm = TRUE)
  )

# Print the summary statistics
print(summary_stats)

Plot of the two figures for Experiment 3


Figure_1C <- grid.arrange(ResponsePlot,ConsistencyPlot,ncol = 1)

EXPERIMENT 4 (Author: Talip Ata Aydin)

Loading the libraries


# Load everything else first
suppressWarnings(suppressMessages(library(readr)))
suppressWarnings(suppressMessages(library(tidyr)))
suppressWarnings(suppressMessages(library(ggplot2)))
suppressWarnings(suppressMessages(library(tidyverse)))
suppressWarnings(suppressMessages(library(psych)))
suppressWarnings(suppressMessages(library(readxl)))  
suppressWarnings(suppressMessages(library(patchwork)))
suppressWarnings(suppressMessages(library(caTools)))
suppressWarnings(suppressMessages(library(car)))
suppressWarnings(suppressMessages(library(quantmod)))
suppressWarnings(suppressMessages(library(MASS)))
suppressWarnings(suppressMessages(library(corrplot)))
suppressWarnings(suppressMessages(library(effects)))
suppressWarnings(suppressMessages(library(writexl)))
suppressWarnings(suppressMessages(library(tidytable)))   
suppressWarnings(suppressMessages(library(stringr)))
suppressWarnings(suppressMessages(library(ape)))
suppressWarnings(suppressMessages(library(grid)))
suppressWarnings(suppressMessages(library(gridExtra)))
suppressWarnings(suppressMessages(library(dplyr)))

Loading the data

demo_data <- read_excel("demo_data.xlsx",
                        sheet = "Sheet1")
Error: `path` does not exist: ‘demo_data.xlsx’

MAIN TASK #############

We will create a dataframe for the main task, since the order of the sliders were randomized across 6 conditions, there are 6 different task names.

monra = music or not ratings (What do you think this is? 0 = not-music, 100 = music, all features are also rated on sliders from 0 to 100.)

ratings <- all_data %>%
  dplyr::select(!monra) %>%
  filter(task_name %in% c("Categorization", "Categorization2", "Categorization3", "Categorization4", "Categorization5", "Categorization6")) %>%
  left_join(
    all_data %>%
      filter(task_name %in% c("Music_or_not")) %>%
      dplyr::select(exp_subject_id, audio_name, monra),
    join_by(exp_subject_id, audio_name)
  ) %>%
  filter(!audio_group == "signal") %>%
  dplyr::select(exp_subject_id, audio_name, monra, pulse, rhythm, repetition, melody, instrumental, timbre, tempo, intentionality, harmony, complexity, pag)


#Now the long format of the same dataframe

ratings_long <- pivot_longer(ratings, 
                         cols = c(monra, pulse, rhythm, repetition, melody, instrumental, timbre, tempo, intentionality, harmony, complexity), # select columns to pivot
                         names_to = "variable",     # new column name for variable names
                         values_to = "value") %>%
   mutate(levels = case_when(
    variable %in% c("instrumental", "intentionality", "complexity", "repetition") ~ 3,
    variable %in% c("harmony", "melody", "rhythm") ~ 2,
    variable %in% c("timbre", "pulse", "tempo") ~ 1,
    TRUE ~ NA_integer_  # Default case if none of the conditions match
  ))

ratings_long_wo_monra <- ratings_long %>%
  filter(!variable == "monra")
ratings_long_music <- ratings_long %>%
  filter(variable == "monra")

ratings_long2 <- pivot_longer(ratings, 
                         cols = c(pulse, rhythm, repetition, melody, instrumental, timbre, tempo, intentionality, harmony, complexity), # select columns to pivot
                         names_to = "variable",     # new column name for variable names
                         values_to = "value") %>%
   mutate(levels = case_when(
    variable %in% c("instrumental", "intentionality", "complexity", "repetition") ~ 3,
    variable %in% c("harmony", "melody", "rhythm") ~ 2,
    variable %in% c("timbre", "pulse", "tempo") ~ 1,
    TRUE ~ NA_integer_  # Default case if none of the conditions match
  ))

Creating the dataframes for musical sophistication index (Gold-MSI) and auditory imagery (vividness, BAIS-V)

ratings_scales <- dplyr::select(all_data, exp_subject_id, task_name, audio_name, audio_group, monra, pulse, repetition, rhythm, melody, instrumental, timbre, tempo, intentionality, harmony, complexity, ae_01, ae_02, ae_05, ae_07, baisv_01, baisv_02, baisv_03, baisv_04, baisv_05, baisv_06, baisv_07, baisv_08, baisv_09, baisv_10, baisv_11, baisv_12, baisv_13, baisv_14, mt_01, mt_02, mt_03, mt_06, mt_07, pa_04, pa_08, sa_01, sa_02, sa_03, sa_04, sa_05, sa_06, em_04)

ratings <- all_data %>%
  dplyr::select(exp_subject_id, task_name, audio_name, audio_group, monra, pulse, repetition, rhythm, melody, instrumental, timbre, tempo, intentionality, harmony, complexity) %>%
  na.omit()


ratings <- all_data %>%
  filter(task_name %in% c("Categorization", "Categorization2", "Categorization3", "Categorization4", "Categorization5", "Categorization6")) %>%
  dplyr::select(exp_subject_id, audio_name, pulse, repetition, rhythm, melody, instrumental, timbre, tempo, intentionality, harmony, complexity) %>%
  left_join(
    all_data %>%
      filter(!audio_group == "signal") %>%
      filter(task_name %in% c("Music_or_not")) %>%
      dplyr::select(exp_subject_id, audio_name, monra),
    join_by(exp_subject_id, audio_name)
  )

ratings <- merge(ratings, PAGG, by = "audio_name")

Filter only the categorization task and then filter out the signal sounds


#Only ratings of perceptual features

features_data <- ratings_scales %>%
  filter(task_name %in% c("Categorization", "Categorization2", "Categorization3", "Categorization4", "Categorization5", "Categorization6"),
         !audio_group == "signal") %>%
  dplyr::select(exp_subject_id, audio_name, pulse, rhythm, repetition, melody, instrumental, timbre, tempo, intentionality, harmony, complexity)

#Only music or not ratings
monra_data <- ratings_scales %>%
  filter(task_name %in% c("Music_or_not"),
         !audio_group == "signal") %>%
  dplyr::select(exp_subject_id, audio_name, monra)

write_xlsx(monra_data, "monra_data.xlsx")
Error in write_xlsx(monra_data, "monra_data.xlsx") : 
  could not find function "write_xlsx"

Data Frames for MM1 analysis


monra_mm1 <- monra_data %>%
  pivot_wider(names_from = audio_name, values_from = monra)

pulse_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, pulse) %>%
  pivot_wider(names_from = audio_name, values_from = pulse)

repetition_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, repetition) %>%
  pivot_wider(names_from = audio_name, values_from = repetition)

rhythm_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, rhythm) %>%
  pivot_wider(names_from = audio_name, values_from = rhythm)

melody_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, melody) %>%
  pivot_wider(names_from = audio_name, values_from = melody)

instrumental_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, instrumental) %>%
  pivot_wider(names_from = audio_name, values_from = instrumental)

timbre_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, timbre) %>%
  pivot_wider(names_from = audio_name, values_from = timbre)

tempo_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, tempo) %>%
  pivot_wider(names_from = audio_name, values_from = tempo)

intentionality_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, intentionality) %>%
  pivot_wider(names_from = audio_name, values_from = intentionality)

harmony_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, harmony) %>%
  pivot_wider(names_from = audio_name, values_from = harmony)

complexity_mm1 <- features_data %>%
  dplyr::select(exp_subject_id, audio_name, complexity) %>%
  pivot_wider(names_from = audio_name, values_from = complexity)

A more descriptive DF that we will use, the mean ratings of all sliders (monra + features) at the STIMULUS level!

audio_descriptives <- ratings %>%
  group_by(audio_name) %>%
  summarize(
            mean_monra = mean(monra, na.rm = TRUE),
            mean_pulse = mean(pulse, na.rm = TRUE),
            mean_repetition = mean(repetition, na.rm = TRUE),
            mean_rhythm = mean(rhythm, na.rm = TRUE),
            mean_melody = mean(melody, na.rm = TRUE),
            mean_instrumental = mean(instrumental, na.rm = TRUE),
            mean_timbre = mean(timbre, na.rm = TRUE),
            mean_tempo = mean(tempo, na.rm = TRUE),
            mean_intentionality = mean(intentionality, na.rm = TRUE),
            mean_harmony = mean(harmony, na.rm = TRUE),
            mean_complexity = mean(complexity, na.rm = TRUE))

audio_descriptives <- merge(audio_descriptives, PAGG, by = "audio_name")


audio_descriptives_long <- pivot_longer(audio_descriptives,
                                  cols = c(mean_monra, mean_pulse, mean_rhythm, mean_repetition, mean_melody, mean_instrumental, 
                                                 mean_timbre, mean_tempo, mean_intentionality, mean_harmony, mean_complexity), 
                                  names_to = "variable",    
                                  values_to = "value")

We do the k-means clustering here. This is because the clusters will then be used for further analysis etc. and we thought it makes more sense to put the cluster analysis here.

Because R gives random numbers to clusters each time we run the analyses, we will simply upload the file with clusters, the code to find those clusters are commented out.

We decided that a 3-cluster-solution is the best. Looking at them, there is one with music stimuli (music cluster), another with not-music stimuli (not-music cluster, although in the code you might see it as “non-music”), and then a cluster in between, which we call the “ambiguous cluster”.

suppressWarnings(suppressMessages(library(readxl)))

# # Assuming you have loaded your data frame 'audio_descriptives' correctly
# justmeans <- dplyr::select(audio_descriptives, audio_name, mean_monra)
# 
# # Perform k-means clustering
# kmm <- kmeans(justmeans$mean_monra, 3, nstart = 50, iter.max = 15)
# print(kmm)
# print(kmm$betweenss / kmm$totss)
# 
# # Method 1: Elbow Method for finding the optimal number of clusters
# set.seed(123)
# 
# # Compute and plot wss for k = 2 to k = 15
# k.max <- 15
# data <- justmeans$mean_monra  # Ensure this is the correct column name
# data <- na.omit(data)  # Remove NA values if any
# 
# wss <- sapply(1:k.max, function(k) {
#   kmeans(data, k, nstart = 50, iter.max = 15)$tot.withinss
# })
# 
# # Plot the results
# plot(1:k.max, wss,
#      type = "b", pch = 19, frame = FALSE, 
#      xlab = "Number of clusters",
#      ylab = "Total Within-Clusters Sum of Squares")
# 
# 
# 
# justmeans <- justmeans %>% 
#   mutate(cluster = kmm$cluster)
# 
# # View the first few rows of the updated data frame
# head(justmeans)

#write_xlsx(justmeans, "justmeans.xlsx")


#Loading the data with stimuli, cluster labels, and cluster numbers (numbers will be irrelevant)

justmeans <- read_excel("justmeans.xlsx",
           sheet = "Sheet1")

# Create a separate data frame called audio_clusters for clarity and future use
audio_clusters <- justmeans %>% 
  dplyr::select(audio_name, cluster) %>%
  mutate(label = case_when(
    cluster == 1 ~ "music",
    cluster == 2 ~ "ambiguous",
    cluster == 3 ~ "non-music"))

audio_clusters <- audio_clusters %>%
  mutate(clean_names = audio_name %>%
           gsub("^(M_|N_)", "", .) %>%  # Remove M_ or N_ at the start
           gsub("\\.mp3$", "", .) %>%  # Remove .mp3 at the end
           gsub("_", " ", .) %>%       # Replace underscores with spaces
           str_to_title()              # Capitalize each word
         )

audio_descriptives <- merge(audio_descriptives, audio_clusters, by = "audio_name")

#Including the cluster column to other dataframes

ratings <- ratings %>%
  left_join(audio_clusters %>%
              dplyr::select(audio_name, label, cluster),
            by = "audio_name")

ratings_long <- ratings_long %>%
  left_join(audio_clusters %>%
              dplyr::select(audio_name, label),
            by = "audio_name")

ratings_long_wo_monra <- ratings_long_wo_monra %>%
  left_join(audio_clusters %>%
              dplyr::select(audio_name, label),
            by = "audio_name")

ratings_lme <- ratings

write_xlsx(audio_descriptives, "audio_descriptives.xlsx")

write_xlsx(ratings, "ratings.xlsx")

A dataframe for the means of all audios


audio_features <- dplyr::select(audio_descriptives, audio_name, mean_monra, mean_pulse, mean_rhythm, mean_repetition, mean_melody, mean_instrumental, mean_timbre, mean_tempo, mean_intentionality, mean_harmony, mean_complexity, label)

write_xlsx(audio_features, "audio_features.xlsx")

Participant means, average values at the participant level


participant_means <- ratings %>%
  group_by(exp_subject_id) %>%
  summarize(across(.cols = c(monra, pulse, rhythm, repetition, melody, instrumental, timbre, tempo, intentionality, harmony, complexity), .fns = mean))

Calculate Gold-MSI


gold <- dplyr::select(all_tasks, exp_subject_id, ae_01, ae_02, ae_05, ae_07, mt_01, mt_02, mt_03, mt_06, mt_07, pa_04, pa_08, sa_01, sa_02, sa_03, sa_04, sa_05, sa_06, em_04)

gold <- aggregated_data <- aggregate(. ~ exp_subject_id, data = gold, FUN = function(x) x[!is.na(x)][1])

gold2<-dplyr::select(gold, ! exp_subject_id)

keys_gold <- c("sa_05", "sa_04", "mt_03", "mt_07", "pa_08")

rec <-  psych::reverse.code(keys = keys_gold, items = gold2, mini = 1, maxi = 7) 

# View(rec)
rec <- as.data.frame(rec)

#GM_sum 
rec$gold=rowSums(cbind(rec$ae_01,rec$ae_02,rec$ae_05,rec$ae_07,rec$em_04,rec$mt_01,rec$mt_02,rec$`mt_03-`,rec$mt_06,rec$`mt_07-`,rec$pa_04,rec$`pa_08-`,rec$sa_01,rec$sa_02,rec$sa_03,rec$`sa_04-`,rec$`sa_05-`,rec$sa_06))

rec$exp_subject_id <- gold$exp_subject_id
gold_score <- dplyr::select(rec, exp_subject_id, gold)

Calculate BAIS-V


bais <- dplyr::select(all_tasks, exp_subject_id, baisv_01, baisv_02, baisv_03, baisv_04, baisv_05, baisv_06, baisv_07, baisv_08, baisv_09, baisv_10, baisv_10, baisv_11, baisv_12, baisv_13, baisv_14)
bais <- na.omit(bais)
rec <- as.data.frame(bais)

#Mean_score
rec$bais=rowMeans(cbind(rec$baisv_01,rec$baisv_02,rec$baisv_03,rec$baisv_04,rec$baisv_05,rec$baisv_06,rec$baisv_07,rec$baisv_08,rec$baisv_09,rec$baisv_10,rec$baisv_11,rec$baisv_12,rec$baisv_13,rec$baisv_14))

BAIS_score<-dplyr::select(rec,bais)
BAIS_score <- cbind(BAIS_score, bais$exp_subject_id)
colnames(BAIS_score)[colnames(BAIS_score) == "BAIS_score$exp_subject_id"] <- "exp_subject_id"

scales <-cbind(gold_score, BAIS_score)

Calculate Openness


openness <- dplyr::select(all_tasks, exp_subject_id, open1, open2, open3, open4, open5, open6, open7, open8, open9, open10)

reverse_code <- function(x) {
  return(6 - x)
}

# Apply reverse coding and calculate total_openness
openness <- openness %>%
  mutate(
    open2 = reverse_code(open2),
    open4 = reverse_code(open4),
    open6 = reverse_code(open6),
    open8 = reverse_code(open8),
    open10 = reverse_code(open10)
  ) %>%
  group_by(exp_subject_id) %>%
  summarise(total_openness = sum(c_across(open1:open10), na.rm = TRUE))

# View the result
print(openness)
# A tidytable: 98 × 2
   exp_subject_id total_openness
            <dbl>          <dbl>
 1         937114             39
 2         937115             37
 3         937117             46
 4         937126             44
 5         937138             43
 6         937151             39
 7         937164             36
 8         937267             42
 9         943497             36
10         943525             29
# ℹ 88 more rows
# ℹ Use `print(n = ...)` to see more rows
# Merge all scales in one dataframe
all_scales <- merge(scales, openness, by ="exp_subject_id")
all_scales <- all_scales 


mean(all_scales$total_openness)
[1] 38.18367
sd(all_scales$total_openness)
[1] 6.381912
min(all_scales$total_openness)
[1] 18
max(all_scales$total_openness)
[1] 50
mean(all_scales$bais)
[1] 4.786443
sd(all_scales$bais)
[1] 1.020539
min(all_scales$bais)
[1] 1
max(all_scales$bais)
[1] 6.928571
mean(all_scales$gold)
[1] 71.45918
sd(all_scales$gold)
[1] 19.78397
min(all_scales$gold)
[1] 29
max(all_scales$gold)
[1] 114

Let’s compute how well participants understood the definitions of features that we provided!


understanding <- all_tasks %>%
  dplyr::select(exp_subject_id, pulseund, melodyund, instrumentalund, timbreun, tempound, intentionalityund, harmonyund, complexityund, toneund, rhythmund) %>%
  na.omit() %>%
  group_by(exp_subject_id) %>%
  summarise(total_und = sum(c_across(pulseund:complexityund)))

understanding_perfeature <- all_tasks %>%
  dplyr::select(exp_subject_id, pulseund, melodyund, instrumentalund, timbreun, tempound, intentionalityund, harmonyund, complexityund, toneund, rhythmund) %>%
  na.omit()


understanding_long <- pivot_longer(understanding_perfeature,
                                  cols = c(pulseund, melodyund, instrumentalund, timbreun, 
                                           tempound, intentionalityund, harmonyund, complexityund, toneund, rhythmund), 
                                  names_to = "variable",    
                                  values_to = "value")

understanding <- merge(understanding, all_scales, by ="exp_subject_id")

Let’s compute how often participants listen to different genres

genres <- all_tasks %>%
  filter(task_name %in% c("Genres", "Genres2", "Genres3", "Genres4", "Genres5", "Genre6")) %>%
  dplyr::select(exp_subject_id, top40, pop, rock, classical, noise, experimental, edm) 

genres[is.na(genres)] <- 0

genres <- genres %>%
  mutate(music_diversity = noise + experimental,
         noise_experimental_listen = ifelse(is.na(music_diversity), "no", "yes"))
genres$noise_experimental_listen <- as.factor(genres$noise_experimental_listen)  

all_scales <- all_scales %>%
  left_join(genres %>%
              dplyr::select(exp_subject_id, music_diversity),
            by = "exp_subject_id")  

Calculate the mean age and gender information


mean(demo_data$age)
[1] 34.97959
sd(demo_data$age)
[1] 11.32098
min(demo_data$age)
[1] 18
max(demo_data$age)
[1] 74
table(demo_data$gender)

female   male 
    30     68 

Put the average rating for each participant to the scales df


means_scales <- merge(all_scales, participant_means, by = "exp_subject_id")

means_scales_age <- means_scales %>%
  left_join(demo_data %>%
              dplyr::select(exp_subject_id, age),
              by = "exp_subject_id") 

means_scales_age_genres <- merge(means_scales_age, genres, by = "exp_subject_id")

A DF just for the ambiguous stimuli

ambiguous_stimuli <- ratings %>%
  filter(label == "ambiguous")

ambiguous_participant_means <- ambiguous_stimuli %>%
  group_by(exp_subject_id) %>%
  summarize(mean_monra = mean(monra)) %>%
  dplyr::select(exp_subject_id, mean_monra)

A DF for the descriptive stats for monra

monra_desc_stats <- ratings |> 
  group_by(audio_name) |> 
  summarize(mean_monra = mean(monra),
            sd_monra = sd(monra)) |> 
  left_join(audio_clusters |> 
              dplyr::select(audio_name, label),
            by = "audio_name")

monra_desc_stats$label <- factor(monra_desc_stats$label, levels = c("non-music", "ambiguous", "music"))

Circular cluster plot for the paper, included in Figure 2A

library(ape)
library(grid)
library(gridExtra)

# Reorder the audio_name based on the label to group the clusters
audio_clusters <- audio_clusters[order(audio_clusters$label), ]

audio_clusters$audio_name <- as.character(audio_clusters$audio_name)

# Step 1: Order the dataframe alphabetically including prefixes
audio_clusters <- audio_clusters %>%
  arrange(audio_name) 
audio_clusters$number <- 1:nrow(audio_clusters)  # Assign numbers sequentially


audio_clusters <- audio_clusters %>%
  mutate(clean_names = str_replace(audio_name, '^(.+)\\.mp3$', '\\1')) %>%
  mutate(clean_names = str_to_title(clean_names))


distance_mat <- dist(audio_descriptives$mean_monra, method = 'euclidean')
distance_mat
             1           2           3           4           5           6           7           8           9
2   9.93877551                                                                                                
3  11.68367347  1.74489796                                                                                    
4  12.50000000 22.43877551 24.18367347                                                                        
5   9.28571429 19.22448980 20.96938776  3.21428571                                                            
6   2.65306122 12.59183673 14.33673469  9.84693878  6.63265306                                                
7   3.62244898  6.31632653  8.06122449 16.12244898 12.90816327  6.27551020                                    
8   1.95918367 11.89795918 13.64285714 10.54081633  7.32653061  0.69387755  5.58163265                        
9  10.42857143  0.48979592  1.25510204 22.92857143 19.71428571 13.08163265  6.80612245 12.38775510            
10 12.64285714  2.70408163  0.95918367 25.14285714 21.92857143 15.29591837  9.02040816 14.60204082  2.21428571
11 21.57142857 31.51020408 33.25510204  9.07142857 12.28571429 18.91836735 25.19387755 19.61224490 32.00000000
12 12.53061224  2.59183673  0.84693878 25.03061224 21.81632653 15.18367347  8.90816327 14.48979592  2.10204082
            10          11          12          13          14          15          16          17          18
2                                                                                                             
3                                                                                                             
4                                                                                                             
5                                                                                                             
6                                                                                                             
7                                                                                                             
8                                                                                                             
9                                                                                                             
10                                                                                                            
11 34.21428571                                                                                                
12  0.11224490 34.10204082                                                                                    
            19          20          21          22          23          24          25          26          27
2                                                                                                             
3                                                                                                             
4                                                                                                             
5                                                                                                             
6                                                                                                             
7                                                                                                             
8                                                                                                             
9                                                                                                             
10                                                                                                            
11                                                                                                            
12                                                                                                            
            28          29          30          31          32          33          34          35          36
2                                                                                                             
3                                                                                                             
4                                                                                                             
5                                                                                                             
6                                                                                                             
7                                                                                                             
8                                                                                                             
9                                                                                                             
10                                                                                                            
11                                                                                                            
12                                                                                                            
            37          38          39          40          41          42          43          44          45
2                                                                                                             
3                                                                                                             
4                                                                                                             
5                                                                                                             
6                                                                                                             
7                                                                                                             
8                                                                                                             
9                                                                                                             
10                                                                                                            
11                                                                                                            
12                                                                                                            
            46          47          48          49          50          51          52          53          54
2                                                                                                             
3                                                                                                             
4                                                                                                             
5                                                                                                             
6                                                                                                             
7                                                                                                             
8                                                                                                             
9                                                                                                             
10                                                                                                            
11                                                                                                            
12                                                                                                            
            55          56          57          58          59          60          61          62          63
2                                                                                                             
3                                                                                                             
4                                                                                                             
5                                                                                                             
6                                                                                                             
7                                                                                                             
8                                                                                                             
9                                                                                                             
10                                                                                                            
11                                                                                                            
12                                                                                                            
            64          65          66          67          68          69          70          71          72
2                                                                                                             
3                                                                                                             
4                                                                                                             
5                                                                                                             
6                                                                                                             
7                                                                                                             
8                                                                                                             
9                                                                                                             
10                                                                                                            
11                                                                                                            
12                                                                                                            
            73          74          75          76          77          78          79          80          81
2                                                                                                             
3                                                                                                             
4                                                                                                             
5                                                                                                             
6                                                                                                             
7                                                                                                             
8                                                                                                             
9                                                                                                             
10                                                                                                            
11                                                                                                            
12                                                                                                            
            82          83          84          85          86          87          88          89
2                                                                                                 
3                                                                                                 
4                                                                                                 
5                                                                                                 
6                                                                                                 
7                                                                                                 
8                                                                                                 
9                                                                                                 
10                                                                                                
11                                                                                                
12                                                                                                
 [ reached 'max' / getOption("max.print") -- omitted 78 rows ]
# Fitting Hierarchical clustering Model to training dataset
set.seed(240) # Setting seed
Hierar_cl <- hclust(distance_mat, method = "average")


# Assuming 'Hierar_cl' is your hclust result and 'fit' contains cluster assignments
phylo_tree <- as.phylo(Hierar_cl)  # Convert hclust to phylo object
fit <- cutree(Hierar_cl, k = 3)

# Define your cluster colors
# Ensure 'fit' is a vector containing cluster assignments for each tip
colors <- c("red", "blue", "green")  # 1 = red, 2 = blue, 3 = green
tip_colors <- colors[fit]  # Map the cluster assignments to colors

# Plot the circular dendrogram with color-coded tips
plot(phylo_tree, 
     type = "fan",       # Circular plot
     tip.color = tip_colors,  # Color tips based on clusters
     label.offset = 0.01,  # Space between tips and labels
     cex = 1.6,           # Text size
     show.tip.label = TRUE)  # Show labels (audio names)



# Define colors for each cluster
label_colors <- c("music" = "red", "ambiguous" = "blue", "non-music" = "green")

# Create a blank plot for printing the text
grid.newpage()

# Set up the column positions
x_positions <- c(0.1, 0.4, 0.7)  # X coordinates for the 3 columns

# Loop through each row and assign text to the correct column and row position
for (i in 1:nrow(audio_clusters)) {
  # Determine the column (1st, 2nd, or 3rd column)
  column <- ((i - 1) %/% 30) + 1
  row <- (i - 1) %% 30 + 1
  
  # Calculate the y position for each row (invert row index for grid positioning)
  y_position <- 1 - (row * 0.03)  # Adjust spacing between rows

  # Print the text in the correct column, color-coded by cluster
  grid.text(
    label = paste(audio_clusters$number[i], "-", audio_clusters$clean_names[i]), 
    x = x_positions[column], 
    y = y_position, 
    gp = gpar(col = label_colors[audio_clusters$label[i]], fontsize = 20),
    just = "left"
  )
}

NA
NA
NA
NA
NA

Plotting the participants and audios ordered by mean (Figure 2B)

The first column represent the mean music ratings ordered from high (on top) to low (on the bottom). Then, every other column is the ranking of each participant’s music ratings.

#Do this otherwise it overrides dplyr
detach("package:tidytable", unload = TRUE)


# Reshaping the dataframe
monra_mm1_long <- monra_mm1 %>%
  pivot_longer(
    cols = -exp_subject_id,  # Keep exp_subject_id, gather other columns
    names_to = "audio_name",  # The names of the audio columns will go to this new column
    values_to = "rating"      # The ratings will go to this new column
  )

# Now pivot wider so that exp_subject_id becomes columns
monra_mm1_wide <- monra_mm1_long %>%
  pivot_wider(
    names_from = exp_subject_id,  # The exp_subject_id values become new columns
    values_from = rating          # Values come from the rating column
  )

# Print the reshaped dataframe
print(monra_mm1_wide)

monra_mean_participants <- monra_mm1_wide %>%
  left_join(audio_descriptives %>% dplyr::select(audio_name, mean_monra), by = "audio_name") %>%
  relocate(mean_monra, .after = audio_name) %>%
  left_join(audio_clusters %>% dplyr::select(audio_name, label), by = "audio_name") %>%
  relocate(label, .after = mean_monra)

# Step 1: Reshape the original data to long format for participant ratings
long_data <- monra_mean_participants %>%
  pivot_longer(
    cols = -c(audio_name, mean_monra, label),  # Exclude non-participant columns
    names_to = "participant_id", 
    values_to = "rating"
  ) %>%
  group_by(participant_id) %>%
  arrange(rating, .by_group = TRUE) %>%
  mutate(rank = row_number())  # Assign rank based on the order of ratings within each participant

# Step 2: Create a long format for mean_monra
mean_monra_long <- monra_mean_participants %>%
  dplyr::select(audio_name, mean_monra, label) %>%
  mutate(participant_id = "mean_monra", rating = mean_monra) %>%
  dplyr::select(audio_name, participant_id, rating, label)

# Step 3: Combine both long formats
combined_long_data <- bind_rows(long_data, mean_monra_long)

# Step 4: Adjust the participant_id to make mean_monra first
combined_long_data <- combined_long_data %>%
  mutate(participant_id = factor(participant_id, levels = c("mean_monra", unique(long_data$participant_id))))  # Ensures mean_monra is first

# Step 5: Rank the combined data
combined_long_data <- combined_long_data %>%
  group_by(participant_id) %>%
  arrange(rating, .by_group = TRUE) %>%
  mutate(rank = row_number())  # Assign rank for all participants including mean_monra

# Step 6: Create the plot
ggplot(combined_long_data, aes(x = participant_id, y = rank, fill = label)) +
  geom_tile() +
  scale_fill_manual(
    values = c("music" = "red", "ambiguous" = "blue", "non-music" = "green"),
    labels = c("music" = "Music", "ambiguous" = "Ambiguous", "non-music" = "Not-music")
  ) +
  labs(
    x = "Participants",
    y = "Ranking of Stimuli",
    title = " ",
    fill = "Cluster"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_blank(),
    axis.title.x = element_text(size = 30),
    axis.text.y = element_blank(),
    axis.title.y = element_text(size = 30),
    panel.grid = element_blank(),
    legend.text = element_text(size = 15),
    legend.title = element_text(size = 20),
    axis.text.x.left = element_text(
      ifelse(unique(combined_long_data$participant_id) == "mean_monra", "black", "transparent")
    )
  )

NA
NA

Experiment 4 Analyses

monra_mean_participants %>%
  pivot_longer(
    cols = -c(audio_name, mean_monra, label),
    names_to = "participant_id", 
    values_to = "rating"
  )  %>%
  table(sapply(long_data$rating, class))```
Error: attempt to use zero-length variable name
audio_descriptives <- read_excel("audio_descriptives.xlsx",
                                  sheet = "Sheet1")

monra_data <- read_excel("monra_data.xlsx",
                         sheet = "Sheet1")

MM1 for monra

Overall MM1 value for music ratings is .87. This is very high, so participants to agree with each other. This is reported in the paper.


MM1_revised <- function(df){
  #save & remove subj id
  id <- df[, 1]
  df <- as.matrix(df[,-1])
  
  #Compute means minus one
  means <- matrix(0, nrow = nrow(df), ncol = ncol(df))
  for(j in 1:nrow(df)){
    means[j,] <- colMeans(df[-j,])
  }
  
  #Compute correlations between means minus ones and ones ratings
  mm1 <- sapply(1:nrow(df), function(.x) cor(df[.x,], means[.x,]))
  
  #transform correlations into z scores (r to z Fisher)
  z_scores <- sapply(mm1, function(x) log((1 + x)/(1 - x))) * .5 
  
  #save average correlation (z average to r average Fisher) and correlations per rater
  result <-  list(MM1 = (exp(2 * (mean(z_scores))) - 1)/(exp( 2 * (mean(z_scores))) + 1), 
                  raw = data.frame(id, mm1 = mm1, mm1_z = z_scores))
  result
}

#I wanted to see the MM1 list pls
MM1_List <- MM1_revised(monra_mm1)

MM1_L <- as.data.frame(MM1_List$raw)

MM1_List
$MM1
[1] 0.8693654

$raw
MM1_List$MM1
[1] 0.8693654

MM1 for each features (Reported)

This varies… For higher level features, there is more agreement, for lower level features, there is less…


MM1_repetition <- MM1_revised(repetition_mm1)
MM1_repetition$MM1
[1] 0.4167283
MM1_pulse <- MM1_revised(pulse_mm1)
MM1_pulse$MM1
[1] 0.6281115
MM1_rhythm <- MM1_revised(rhythm_mm1)
MM1_rhythm$MM1
[1] 0.6734365
MM1_melody <- MM1_revised(melody_mm1)
MM1_melody$MM1
[1] 0.787064
MM1_instrumental <- MM1_revised(instrumental_mm1)
MM1_instrumental$MM1
[1] 0.8323992
MM1_timbre <- MM1_revised(timbre_mm1)
MM1_timbre$MM1
[1] 0.6026743
MM1_tempo <- MM1_revised(tempo_mm1)
MM1_tempo$MM1
[1] 0.5776043
MM1_intentionality <- MM1_revised(intentionality_mm1)
MM1_intentionality$MM1
[1] 0.7481585
MM1_harmony <- MM1_revised(harmony_mm1)
MM1_harmony$MM1
[1] 0.7194582
MM1_complexity <- MM1_revised(complexity_mm1)
MM1_complexity$MM1
[1] 0.6734471

Krippendorff’s alpha for each rating, at the group level. (Reported)


monra_krip <- monra_mm1 %>%
  dplyr::select(!exp_subject_id)

monra_krip <- as.matrix(monra_krip)

kripp.alpha(monra_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.684 
intentionality_krip <- intentionality_mm1 %>%
  dplyr::select(!exp_subject_id)

intentionality_krip <- as.matrix(intentionality_krip)

kripp.alpha(intentionality_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.478 
instrumental_krip <- instrumental_mm1 %>%
  dplyr::select(!exp_subject_id)

instrumental_krip <- as.matrix(instrumental_krip)

kripp.alpha(instrumental_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.622 
complexity_krip <- complexity_mm1 %>%
  dplyr::select(!exp_subject_id)

complexity_krip <- as.matrix(complexity_krip)

kripp.alpha(complexity_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.367 
repetition_krip <- repetition_mm1 %>%
  dplyr::select(!exp_subject_id)

repetition_krip <- as.matrix(repetition_krip)

kripp.alpha(repetition_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.115 
melody_krip <- melody_mm1 %>%
  dplyr::select(!exp_subject_id)

melody_krip <- as.matrix(melody_krip)

kripp.alpha(melody_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.539 
rhythm_krip <- rhythm_mm1 %>%
  dplyr::select(!exp_subject_id)

rhythm_krip <- as.matrix(rhythm_krip)

kripp.alpha(rhythm_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.369 
harmony_krip <- harmony_mm1 %>%
  dplyr::select(!exp_subject_id)

harmony_krip <- as.matrix(harmony_krip)

kripp.alpha(harmony_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.422 
timbre_krip <- timbre_mm1 %>%
  dplyr::select(!exp_subject_id)

timbre_krip <- as.matrix(timbre_krip)

kripp.alpha(timbre_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.285 
tempo_krip <- tempo_mm1 %>%
  dplyr::select(!exp_subject_id)

tempo_krip <- as.matrix(tempo_krip)

kripp.alpha(tempo_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.247 
pulse_krip <- pulse_mm1 %>%
  dplyr::select(!exp_subject_id)

pulse_krip <- as.matrix(pulse_krip)

kripp.alpha(pulse_krip, method = "interval")
 Krippendorff's alpha

 Subjects = 90 
   Raters = 98 
    alpha = 0.31 

Linear Mixed Effects Model to predict MoNRa by perceptual features (reported)

ACOUSTIC FEATURE SELECTION

Get and prepare data:


options(scipen=999)

#The features have been extracted already, we read in the data

acoustics_mir<- read_excel("essentia_acoustics_2.xlsx",
    sheet = "Sheet1") 

# We clean the names

acoustics_mir$audio_name <- sub("\\.mp3.*", ".mp3", acoustics_mir$audio_name)

# Get the column names
col_names <- colnames(acoustics_mir)
col_names

# Remove "" from the end of each column name
clean_col_names <- gsub('""$', '', col_names)

# Assign the cleaned column names back to the dataframe
colnames(acoustics_mir) <- clean_col_names

# Check the cleaned column names
print(colnames(acoustics_mir))

acoustics_mir <- acoustics_mir %>%
  left_join(audio_descriptives %>%
              dplyr::select(audio_name, label, mean_monra),
            by = "audio_name") %>%
  dplyr::select(audio_name, label, mean_monra, everything())


acoustics_mir <- acoustics_mir %>%
  dplyr::select(!id) %>%
  dplyr::select(!average_loudness.value) 

acoustics_mir <- acoustics_mir %>% dplyr::select(, 1:251)

names(acoustics_mir)

Scale data:


scaled_mir_ <- acoustics_mir |> 
  select(!mean_monra) |> 
  mutate_if(is.numeric,scale)

# Scale columns 4 to 251
scaled_columns <- scale(acoustics_mir[, 4:251])

# Combine the unscaled first three columns with the scaled columns
acoustics_mir_scaled <- cbind(acoustics_mir[, 1:3], as.data.frame(scaled_columns))

#rownames(numeric_mir) <- scaled_mir_[,1]

str(numeric_mir)
names(scaled_mir_)
names(acoustics_mir)

First clean out obviously redundant features. barkbands.dmean_01-27 are the same as frequency_bands.dmean_01-27; subband_mean/std (2-10) same as mfcc2_mean/std; also remove spectral_energyband_low.dvar

These are 72 acoustic features that do not have correlations above .75 with each other.

highly_corr<-fuzzySim::corSelect(acoustics_mir_scaled[, 4:251], cor.thresh = .75, var.cols =1:248)

redundant_variables<-highly_corr$excluded.vars[1:176]

count(highly_corr$high.correlations)

numeric_mir_excluded <- numeric_mir %>% dplyr::select(!all_of(redundant_variables)) 

acoustics_mir_scaled_nocollinear <- acoustics_mir_scaled %>% dplyr::select(!all_of(redundant_variables)) 


names(numeric_mir)

Now, we correlate each acoustic feature with mean music ratings to see how the relationships look like


acoustic_features_to_correlate <- acoustics_mir_scaled_nocollinear[, 
                sapply(acoustics_mir_scaled_nocollinear, is.numeric) & 
                names(acoustics_mir_scaled_nocollinear) != "mean_monra"
              ]

# Compute correlations
full_cor_results <- sapply(acoustic_features_to_correlate, function(column) {
  cor(column, acoustics_mir_scaled_nocollinear$mean_monra, use = "complete.obs")
})

# Format results
full_cor_df <- data.frame(
  Variable = names(full_cor_results),
  Correlation = full_cor_results,
  stringsAsFactors = FALSE
)

# Order by absolute correlation
full_cor_df <- full_cor_df[order(-abs(full_cor_df$Correlation)), ]

# Show result
print(full_cor_df)

Now, select the 10 acoustic features that have the abolsute highest correlation to mean_monra

acoustics_cluster_absolute_corr <- dplyr::select(acoustics_mir_scaled_nocollinear, audio_name, label, mean_monra, pitch_salience.dmean, silence_rate_30dB.dmean, scvalleys.dvar_01, gfcc.dmean_11, gfcc.dmean_09, zerocrossingrate.dvar, pitch_instantaneous_confidence.dvar, spectral_contrast.dvar_01, barkbands.dmean_23, gfcc.dmean_13)

write_xlsx(acoustics_cluster_absolute_corr, "acoustics_cluster_absolute_corr.xlsx")


write_xlsx(acoustics_mir_scaled_nocollinear, "acoustics_mir_scaled_nocollinear.xlsx")

Comparing acoustic vs. perceptual features in predicting a music category

Packages


suppressWarnings(suppressMessages(library(broom.mixed)))
suppressWarnings(suppressMessages(library(cowplot)))
suppressWarnings(suppressMessages(library(factoextra)))
suppressWarnings(suppressMessages(library(ggfortify)))
suppressWarnings(suppressMessages(library(lme4)))
suppressWarnings(suppressMessages(library(lmerTest)))
suppressWarnings(suppressMessages(library(ordinal)))
suppressWarnings(suppressMessages(library(rcompanion)))
suppressWarnings(suppressMessages(library(stats)))
suppressWarnings(suppressMessages(library(writexl)))

Reading in DFs

acoustics_mir_scaled_nocollinear <- read_excel("acoustics_mir_scaled_nocollinear.xlsx",
    sheet = "Sheet1") 

audio_descriptives <- read_excel("audio_features.xlsx",
    sheet = "Sheet1") 

monra_data <- read_excel("monra_data.xlsx",
    sheet = "Sheet1") 

acoustics_cluster_absolute_corr <- read_excel("acoustics_cluster_absolute_corr.xlsx",
    sheet = "Sheet1") 

PCA WITH PERCEPTUAL FEATURES

We reduce the dimensionality of our perceptual features to later use these principal components in modeling. We select the first two principal components here.


pca_result_perceptual <- prcomp(audio_descriptives[,3:12], center = TRUE, scale. = TRUE)


fviz_eig(pca_result_perceptual, addlabels = TRUE)

eig.val_per <- get_eigenvalue(pca_result_perceptual)
eig.val_per

# number of PCs to keep
pcdims_per = 10

# Print eigenvalues
eig.val_per[c(1:pcdims_per),]

res.feats_per <- get_pca_var(pca_result_perceptual)

contribdf_per  = as.data.frame(res.feats_per$contrib[,c(1:pcdims_per)])
round(contribdf_per, digits=2)

loadings_per <- pca_result_perceptual$rotation
loadings_per[,c(1:2)]

res.ind_per <- get_pca_ind(pca_result_perceptual)

pc_scores_per = pca_result_perceptual$x

pca_data_perc <- as.data.frame(pca_result_perceptual$x)
pca_data_perc$label <- mir_monra2$label

audio_descriptives$PC1 = pc_scores_per[,1]*-1
audio_descriptives$PC2 = pc_scores_per[,2]

# Now re-run the plotting
fviz_pca_biplot(pca_result_perceptual,
                label = "var",        # only variable names
                habillage = mir_monra2$label,
                addEllipses = TRUE,
                col.var = "black",
                repel = TRUE)

fviz_eig(pca_result_perceptual, addlabels = TRUE, ylim = c(0, 100)) +
  theme_minimal() +  # Minimal theme for a clean look
  theme(
    panel.grid.major = element_blank(),    # Remove major grid lines
    panel.grid.minor = element_blank(),    # Remove minor grid lines
    panel.background = element_blank(),    # Remove background color
    axis.line = element_line(colour = "black"),  # Add axis lines
    legend.position = "NONE",             # Remove the legend
    text = element_text(size = 16)) 

PCA to reduce the number of acoustic features, we select the first 2 principal components.

acoustics_cluster_absolute_corr <- acoustics_cluster_absolute_corr %>%
  mutate(order = ifelse(label == "non-music", 1,
                 ifelse(label == "ambiguous", 2,
                 ifelse(label == "music", 3, NA))))

acoustics_cluster_absolute_corr$order <- as.factor(acoustics_cluster_absolute_corr$order)


pca_result_abs <- prcomp(acoustics_cluster_absolute_corr[4:13], center = TRUE, scale. = FALSE)

fviz_eig(pca_result_abs, addlabels = TRUE, ylim = c(0, 100)) +
  theme_minimal() +  # Minimal theme for a clean look
  theme(
    panel.grid.major = element_blank(),    # Remove major grid lines
    panel.grid.minor = element_blank(),    # Remove minor grid lines
    panel.background = element_blank(),    # Remove background color
    axis.line = element_line(colour = "black"),  # Add axis lines
    legend.position = "NONE",             # Remove the legend
    text = element_text(size = 16)) 

# Plot the first 2 principal components
autoplot(pca_result_abs, 
         data = acoustics_cluster_absolute_corr,
         x = 1,
         y = 2,
         colour = 'label', 
         loadings = TRUE, 
         loadings.label = TRUE,
         loadings.color = "black",
         loadings.label.color = "black",
         loadings.label.repel = TRUE,
         loadings.label.size = 5,
         frame = TRUE,
         frame.type = 'norm') +
  # Customize appearance
  theme_minimal() +  
  theme(
    panel.grid.major = element_blank(),    
    panel.grid.minor = element_blank(),    
    panel.background = element_blank(),    
    axis.line = element_line(colour = "black"),  
    legend.position = "NONE",             
    text = element_text(size = 30)         
  ) +
    scale_color_manual(values = c("music" = "red", "ambiguous" = "blue", "non-music" = "green")) +
   scale_fill_manual(values = c("music" = "red", "ambiguous" = "blue", "non-music" = "green")) + 
  labs(
    title = " ",
    colour = "Mean MONRA Rating"
  ) +
  scale_y_reverse() 


pc_scoreabs = pca_result_abs$x

acoustics_cluster_absolute_corr$PC1ac = pc_scoreabs[,1]
acoustics_cluster_absolute_corr$PC2ac = pc_scoreabs[,2]

Here, we carry out 2 cumulative link models to predict categories using the ordinal package in 2 separate models: acoustic model and the perceptual model


clm_df <- audio_descriptives |> 
  dplyr::select(audio_name, PC1, PC2) |> 
left_join(acoustics_cluster_absolute_corr |> 
            dplyr::select(audio_name, PC1ac, PC2ac),
          by = "audio_name") |> 
left_join(ratings_order |> 
            distinct(audio_name, order), 
          by = "audio_name")

clm_ac_abs <- clm(order ~ PC1ac + PC2ac, data = clm_df)
clm_perceptual <- clm(order ~ PC1 + PC2, data = clm_df)
clm_order_null <- clm(order ~ 1, data = clm_df)

summary(clm_ac_abs)
summary(clm_perceptual)

anova(clm_ac_abs, clm_order_null)
anova(clm_perceptual, clm_order_null)

pR2(lm_order_ac)

###Pseudo r sqaured
nagelkerke(clm_ac_abs, clm_order_null)
nagelkerke(clm_perceptual, clm_order_null)

# Compare AIC
AIC(clm_perceptual, clm_ac_abs)

# Compare BIC
BIC(clm_perceptual, clm_ac_abs)


write_xlsx(clm_df, "clm_df.xlsx")

Hence, the perceptual model outperforms the acoutic model.

Reported PCA Plots (Figure 3A)

library(cowplot)

acoustic_pca_plot <- autoplot(pca_result_abs, 
         data = acoustics_cluster_absolute_corr, 
         colour = 'label', 
         loadings = TRUE, 
         loadings.label = TRUE,
         loadings.color = "black",
         loadings.label.color = "black",
         loadings.label.repel = TRUE,
         loadings.label.size = 5,
         frame = TRUE,
         frame.type = 'norm') +
  # Customize appearance
  theme_minimal() +  # Minimal theme for a clean look
  theme(
    panel.grid.major = element_blank(),    # Remove major grid lines
    panel.grid.minor = element_blank(),    # Remove minor grid lines
    panel.background = element_blank(),    # Remove background color
    axis.line = element_line(colour = "black"),  # Add axis lines
    legend.position = "NONE",             # Remove the legend
    text = element_text(size = 30)         # Increase text size
  ) +
  scale_color_manual(values = c("music" = "red", "ambiguous" = "blue", "non-music" = "green")) +
   scale_fill_manual(values = c("music" = "red", "ambiguous" = "blue", "non-music" = "green")) + # Custom colors
  labs(
    title = " ",
    colour = "Mean MONRA Rating"           # Label for the legend
  ) 

perceptual_pca_plot <- autoplot(pca_result_perceptual, 
         data = audio_descriptives, 
         colour = 'label', 
         loadings = TRUE, 
         loadings.label = TRUE,
         loadings.color = "black",
         loadings.label.color = "black",
         loadings.label.repel = TRUE,
         loadings.label.size = 5,
         frame = TRUE,
         frame.type = 'norm') +
  # Customize appearance
  theme_minimal() +  # Minimal theme for a clean look
  theme(
    panel.grid.major = element_blank(),    # Remove major grid lines
    panel.grid.minor = element_blank(),    # Remove minor grid lines
    panel.background = element_blank(),    # Remove background color
    axis.line = element_line(colour = "black"),  # Add axis lines
    legend.position = "NONE",             # Remove the legend
    text = element_text(size = 30)         # Increase text size
  ) +
  scale_color_manual(values = c("music" = "red", "ambiguous" = "blue", "non-music" = "green")) +
   scale_fill_manual(values = c("music" = "red", "ambiguous" = "blue", "non-music" = "green")) + # Custom colors
  labs(
    title = " ",
    colour = "Mean MONRA Rating"           # Label for the legend
  ) 

legend_pca <- ggplot(data = audio_descriptives, aes(x = 1, y = 1, colour = label)) +
  geom_point() +
  scale_color_manual(values = c("music" = "red", "ambiguous" = "blue", "non-music" = "green"),
                     labels = c("Ambiguous", "Music", "Non-music")) +
  theme_void() + 
  theme(legend.position = "right") +
  guides(colour = guide_legend(override.aes = list(size = 5))) +
  labs(colour = NULL)  # Remove the legend title


loadings_labels <- rownames(pca_result_perceptual$rotation)

# Remove "mean_" from the loadings labels and capitalize the first letter
loadings_labels <- gsub("^mean_", "", loadings_labels)  # Remove "mean_"
loadings_labels <- tools::toTitleCase(loadings_labels)  # Capitalize first letter

# Reassign the modified labels back to the PCA object
rownames(pca_result_perceptual$rotation) <- loadings_labels



cowplot::plot_grid(acoustic_pca_plot, perceptual_pca_plot, legend_pca, ncol = 3, rel_widths = c(0.8, 0.8, 0.1))

Boxplots of mean feature ratings across clusters (Figure 3B)


audio_features_long <- pivot_longer(audio_features,
                                  cols = c(mean_pulse, mean_rhythm, mean_repetition, mean_melody, mean_instrumental, 
                                                 mean_timbre, mean_tempo, mean_intentionality, mean_harmony, mean_complexity), 
                                  names_to = "variable",    
                                  values_to = "value")

audio_features_long$variable <- as.factor(audio_features_long$variable)
audio_features_long$label <- factor(audio_features_long$label, levels = c("music", "ambiguous", "non-music"))


 # Modify the 'variable' column: Remove "mean_" and capitalize the first letter
audio_features_long <- audio_features_long %>%
  mutate(variable = gsub("^mean_", "", variable),      # Remove "mean_"
         variable = tools::toTitleCase(variable))     # Capitalize first letter

audio_features_long$variable <- factor(audio_features_long$variable, 
                                      levels = c("Intentionality", "Instrumental", "Complexity", "Repetition", "Melody", "Harmony", "Rhythm", "Tempo", "Timbre", "Pulse"))


 ratings_cluster_plot_mean <- ggplot(audio_features_long, aes(x = label, y = value, color = label, fill = label)) +
  geom_boxplot(alpha = 0.5, position = position_dodge(width = 0.75)) +
   geom_jitter(alpha = 0.3, size = 1) +
  theme_minimal(base_size = 16) +  # Increase base font size
  theme(
    axis.title = element_text(size = 30),
    plot.title = element_text(size = 18, face = "bold"),
    legend.position = "none",  # Hide legend
    strip.text = element_text(size = 16),  # Facet label text
    panel.grid.major = element_blank(),  # Remove major grid lines
    axis.text.x = element_blank(),
    axis.text.y = element_text(angle = 90, vjust = 0.5, hjust = 1), # Rotate x-axis text
    axis.title.y = element_text(size = 30)
  ) +
   ylim(0,100) +
  labs(
    title = " ",
    x = " ",
    y = "Ratings"
  ) +
  facet_grid(~variable, scales = "free_x", space = "free")  +
  scale_color_manual(values = c("music" = "red", "ambiguous" = "blue", "non-music" = "#3CB371")) +
  scale_fill_manual(values = c("music" = "red", "ambiguous" = "blue", "non-music" = "#3CB371"))

 
ratings_cluster_plot_mean

Radar Chart of mean feature ratings for different clusters (Figure 3C)


audio_descriptives_wo_monra <- audio_descriptives %>%
  dplyr::select(cluster,label, mean_repetition, mean_timbre, mean_tempo, mean_pulse, mean_harmony, mean_melody, mean_rhythm, mean_complexity, mean_intentionality, mean_instrumental)

subgroup_summary_pag <- audio_descriptives_wo_monra %>%
  group_by(label) %>%
  summarise(across(starts_with("mean"), list(mean = mean), .names = "{.col}_{.fn}")) %>%
  rename(mean_pulse = mean_pulse_mean,
         mean_rhythm = mean_rhythm_mean,
         mean_timbre = mean_timbre_mean,
         mean_repetition = mean_repetition_mean,
         mean_tempo = mean_tempo_mean,
         mean_melody = mean_melody_mean,
         mean_harmony = mean_harmony_mean,
         mean_intentionality = mean_intentionality_mean,
         mean_instrumental = mean_instrumental_mean,
         mean_complexity = mean_complexity_mean) 


# Prepare the data by adding max and min rows
max_values <- rep(100, ncol(subgroup_summary_pag) - 1)
min_values <- rep(0, ncol(subgroup_summary_pag) - 1)
data_for_radar <- rbind(max_values, min_values, subgroup_summary_pag[, -1])

# Add row names for clarity (optional)
rownames(data_for_radar) <- c("Max", "Min", paste(subgroup_summary_pag$label))

data_for_radar <- data_for_radar %>%
  rename(Repetition = mean_repetition,
         Timbre = mean_timbre,
         Instrumental = mean_instrumental,
         Intentionality = mean_intentionality,
         Complexity = mean_complexity,
         Melody = mean_melody,
         Harmony = mean_harmony,
         Rhythm = mean_rhythm,
         Pulse = mean_pulse,
         Tempo = mean_tempo)



# Create the radar chart
radarchart(data_for_radar, 
           axistype = 1,
           # Customize the appearance
           pcol = c("blue", "red", "green"),  # Colors for each cluster (nonmusic, ambiguous, music)
           plwd = 4,  # Line width
           plty = 1,  # Line type
           cglcol = "grey",  # Color of the grid lines
           cglty = 1,  # Type of the grid lines
           axislabcol = "black",  # Color of the axis labels
           caxislabels = seq(0, 100, by = 20),  # Axis labels from 0 to 100
           vlcex = 1.5,  # Variable label size
           calcex = 0.9,  # Axis label size
           maxmin = TRUE,  # Ensure max and min values are used
           seg = 5  # Force 5 segments (0, 20, 40, 60, 80, 100)
)

Now, the idea is to try and identify different participant profiles to underIdentifying participant classes

suppressWarnings(suppressMessages(library(broom)))
suppressWarnings(suppressMessages(library(dplyr)))
suppressWarnings(suppressMessages(library(ggfortify)))
suppressWarnings(suppressMessages(library(gt)))
suppressWarnings(suppressMessages(library(jtools)))
suppressWarnings(suppressMessages(library(lcmm)))
suppressWarnings(suppressMessages(library(lme4)))
suppressWarnings(suppressMessages(library(lmerTest)))
suppressWarnings(suppressMessages(library(lmtest)))
suppressWarnings(suppressMessages(library(stringr)))
suppressWarnings(suppressMessages(library(viridis)))
suppressWarnings(suppressMessages(library(xtable)))

We carry out a latent class linear mixed model to identify different participant profiles. We try having up to 6 different profiles (This code will be time consuming, it took us half a day to run.)

Notice that we use “class” and “profile” interchangeably…


m_random <- hlme(
  fixed = monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  random = ~ 1, 
  subject = 'exp_subject_id', 
  ng = 1, 
  data = ratings
)


m_2cl <- hlme(
  fixed = monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  mixture = ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  random = ~ 1,
  subject = 'exp_subject_id',
  ng = 2,
  B = m_random,  # Use m_random as initial values
  data = ratings
)


m_3cl <- hlme(
  fixed = monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  mixture = ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  random = ~ 1,
  subject = 'exp_subject_id',
  ng = 3,
  B = m_random,  # Use m_random as initial values
  data = ratings
)

m_4cl <- hlme(
  fixed = monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  mixture = ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  random = ~ 1,
  subject = 'exp_subject_id',
  ng = 4,
  B = m_random,  # Use m_random as initial values
  data = ratings
)


m_5cl <- hlme(
  fixed = monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  mixture = ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  random = ~ 1,
  subject = 'exp_subject_id',
  ng = 5,
  B = m_random,  # Use m_random as initial values
  data = ratings
)


m_6cl <- hlme(
  fixed = monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  mixture = ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse,
  random = ~ 1,
  subject = 'exp_subject_id',
  ng = 6,
  B = m_random,  # Use m_random as initial values
  data = ratings
)



d<-summarytable(m_random, m_2cl, m_3cl, m_4cl, m_5cl, m_6cl,
                 which = c("G", "loglik", "npm", "BIC", "%class", "entropy")) #??? classes is better

d<- as.data.frame(d)
#view(d)

summary(m_random)
summary(m_2cl)
summary(m_3cl)
summary(m_4cl)
summary(m_5cl)
summary(m_6cl)

logLik_2cl <- m_2cl$loglik
logLik_3cl <- m_3cl$loglik
logLik_4cl <- m_4cl$loglik
logLik_5cl <- m_5cl$loglik
logLik_6cl <- m_6cl$loglik

Selection of the number of classes: 7 criteria (see https://www.displayr.com/work-number-classes-latent-class-analysis/#:~:text=There%20are%20seven%20approaches%20to,your%20own%20Latent%20Class%20Analysis!)

We will look at the BIC and the “no small classes” criteria

No small classes: The basic idea of this approach is that you choose the highest number of classes, such that none of the classes are small (e.g., less than 5% of the sample). This rule has long been used in practice as a part of the idea of domain-usefulness but has recently been discovered also to have some theoretical justification (Nasserinejad, K., van Rosmalen, J., de Kort, W., Lesaffre, E. (2017) Comparison of criteria for choosing the number of classes in Bayesian finite mixture models. PloS one, 12).

Based on these criteria, and table “d”, we picked the solution with 5 classes.

postprob(m_2cl) 
postprob(m_3cl) 
postprob(m_4cl) 
postprob(m_5cl) 
postprob(m_6cl) 

summary(m_5cl)


people_2_classes <- as.data.frame(m_2cl$pprob)
people_3_classes <- as.data.frame(m_3cl$pprob)
people_4_classes <- as.data.frame(m_4cl$pprob)
people_5_classes <- as.data.frame(m_5cl$pprob)
people_6_classes <- as.data.frame(m_6cl$pprob)
# View(people_5_classes)


people_2_classes$twoclasses <- people_2_classes$class
people_3_classes$threeclasses <- people_3_classes$class
people_4_classes$fourclasses <- people_4_classes$class
people_6_classes$sixclasses <- people_6_classes$class

Here, I add the 5-class-solution in the ratings DF.


str(people)

#Class is the solution we picked, it includes 5 classes, numbers from 1 to 5 shows which class a participants has been assigned. 

ratings_class <- ratings %>%
  left_join(people_5_classes %>%
              dplyr::select(exp_subject_id, class),
            by = "exp_subject_id")

The mean ratings of features for each of the 5 profiles.


cluster_means <- aggregate(
  . ~ class, 
  data = ratings_class[, c("class", "intentionality", "instrumental", "complexity", "repetition", "melody", "harmony", "rhythm", "timbre", "tempo", "pulse")], 
  mean
)

cluster_sd <- aggregate(
  . ~ class, 
  data = ratings_class[, c("class", "intentionality","instrumental", "complexity", "repetition", "melody", "harmony", "rhythm", "timbre", "tempo", "pulse")], 
  sd
)

print(cluster_means)
print(cluster_sd)

Now we carry LMMs for each profile. Caution, that we have less participants in each model, increasing the possibility for multicollinarity and other issues…

##1 CLASS

class1_models <- ratings_class %>%
  filter(class == "1") %>%
  lmer(monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse + (1 | exp_subject_id) + (1 | audio_name), data = .)

summary(class1_models)
r.squaredGLMM(class1_models)
car::vif(class1_models) 
rand(class1_models)
performance::icc(class1_model, by_group = TRUE)



class2_models <- ratings_class %>%
  filter(class == "2") %>%
  lmer(monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse + (1 | exp_subject_id) + (1 | audio_name), data = .)

summary(class2_models)
r.squaredGLMM(class2_models)
car::vif(class2_models) 
rand(class2_models)
performance::icc(class2_models, by_group = TRUE)



class3_models <- ratings_class %>%
  filter(class == "3") %>%
  lmer(monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse + (1 | exp_subject_id) + (1 | audio_name), data = .)

summary(class3_models)
r.squaredGLMM(class3_models)
car::vif(class3_model) 
rand(class3_model)
performance::icc(class3_model, by_group = TRUE)


class4_models <- ratings_class %>%
  filter(class == "4") %>%
  lmer(monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse + (1 | exp_subject_id) + (1 | audio_name), data = .)

summary(class4_models)
r.squaredGLMM(class4_models)
car::vif(class4_model) 
rand(class4_model)
performance::icc(class4_model, by_group = TRUE)

class5_models <- ratings_class %>%
  filter(class == "5") %>%
  lmer(monra ~ intentionality + instrumental + complexity + repetition + melody + harmony + rhythm + timbre + tempo + pulse + (1 | exp_subject_id) + (1 | audio_name), data = .)

summary(class5_models)
r.squaredGLMM(class5_models)
car::vif(class5_model) 
rand(class5_model)
performance::icc(class5_model, by_group = TRUE)

Reported figure in the paper

# Generate Viridis color palette with 5 distinct colors
viridis_colors <- viridis_pal(option = "D")(5)

plot_summs(class1_models, class2_models, class3_models, class4_models, class5_models, 
           scale = FALSE, 
           colors = viridis_colors,
           model.names = c("Class 1", "Class 2", "Class 3", "Class 4", "Class 5")) +
  theme_minimal(base_size = 14) +  
  theme(
    axis.text = element_text(size = 25),      
    legend.text = element_text(size = 16),    
    legend.title = element_blank(),  # Adjust legend title size
    plot.title = element_text(size = 20, face = "bold"),
    axis.title.x = element_text(size = 20),
    axis.title.y = element_blank()
  ) +
  labs(color = "Class")  # Rename the legend title

Participant characteristics and classes… We check if participants in these different profiles differ regarding age, auditory imagery, musical sophistication, or openness to experience…


means_scales_age_class <- means_scales_age %>%
  left_join(people_5_classes %>%
              dplyr::select(exp_subject_id, class),
            by = "exp_subject_id")

str(means_scales_age_genres)

# ANOVA for 'bais'
anova_bais <- aov(bais ~ factor(class), data = means_scales_age_class)
summary(anova_bais)

# ANOVA for 'gold'
anova_gold <- aov(gold ~ factor(class), data = means_scales_age_class)
summary(anova_gold)

# ANOVA for 'total_openness'
anova_openness <- aov(total_openness ~ factor(class), data = means_scales_age_class)
summary(anova_openness)

# ANOVA for 'age'
anova_age <- aov(age ~ factor(class), data = means_scales_age_class)
summary(anova_age)

They don’t.

Reported figure of age, BAIS-V, Gold-MSI and Openness scores of all 5 classes


means_scales_age_class$class <- as.factor(means_scales_age_class$class)

ggplot(means_scales_age_class, aes(x = class, y = age, color = class, fill = class)) +
  geom_boxplot(alpha = 0.5, position = position_dodge(width = 0.75)) +
  geom_jitter(alpha = 0.05, size = 1) +
  scale_color_viridis_d() +  
  labs(x = "Class", y = "Age") +
  scale_fill_viridis_d() +   
  theme_minimal(base_size = 16) + 
  theme(
    axis.title = element_text(size = 30),
    plot.title = element_text(size = 18, face = "bold"),
    legend.position = "none",  
    strip.text = element_text(size = 16),  
    panel.grid.major = element_blank(),  
    axis.text.y = element_text(angle = 90, vjust = 0.5, hjust = 1) 
  ) +
  ggplot(means_scales_age_class, aes(x = class, y = bais, color = class, fill = class)) +
  geom_boxplot(alpha = 0.5, position = position_dodge(width = 0.75)) +
  geom_jitter(alpha = 0.05, size = 1) +
  scale_color_viridis_d() +  
  labs(x = "Class", y = "BAIS-V") +
  scale_fill_viridis_d() +   
  theme_minimal(base_size = 16) + 
  theme(
    axis.title = element_text(size = 30),
    plot.title = element_text(size = 18, face = "bold"),
    legend.position = "none",  
    strip.text = element_text(size = 16),  
    panel.grid.major = element_blank(),  
    axis.text.y = element_text(angle = 90, vjust = 0.5, hjust = 1) 
  ) +
  ggplot(means_scales_age_class, aes(x = class, y = gold, color = class, fill = class)) +
  geom_boxplot(alpha = 0.5, position = position_dodge(width = 0.75)) +
  geom_jitter(alpha = 0.05, size = 1) +
  scale_color_viridis_d() +  
  labs(x = "Class", y = "Gold-MSI") +
  scale_fill_viridis_d() +   
  theme_minimal(base_size = 16) + 
  theme(
    axis.title = element_text(size = 30),
    plot.title = element_text(size = 18, face = "bold"),
    legend.position = "none",  
    strip.text = element_text(size = 16),  
    panel.grid.major = element_blank(),  
    axis.text.y = element_text(angle = 90, vjust = 0.5, hjust = 1) 
  ) +
  ggplot(means_scales_age_class, aes(x = class, y = total_openness, color = class, fill = class)) +
  geom_boxplot(alpha = 0.5, position = position_dodge(width = 0.75)) +
  geom_jitter(alpha = 0.05, size = 1) +
  scale_color_viridis_d() +  
  labs(x = "Class", y = "Openness") +
  scale_fill_viridis_d() +   
  theme_minimal(base_size = 16) + 
  theme(
    axis.title = element_text(size = 30),
    plot.title = element_text(size = 18, face = "bold"),
    legend.position = "none",  
    strip.text = element_text(size = 16),  
    panel.grid.major = element_blank(),  
    axis.text.y = element_text(angle = 90, vjust = 0.5, hjust = 1) 
  ) 
  

Let’s summarize the findings in a table!


# Create a list of your models
models <- list(class1 = class1_models, 
               class2 = class2_models, class3 = class3_models, 
               class4 = class4_models, class5 = class5_models)

fixed_effects_list <- purrr::map(models, ~ broom::tidy(.x, effects = "fixed"))

# Combine into a single data frame
fixed_effects <- bind_rows(fixed_effects_list, .id = "class")

fixed_effects <- fixed_effects %>%
  mutate(significance = case_when(
    p.value < 0.001 ~ "***",
    p.value < 0.01  ~ "**",
    p.value < 0.05  ~ "*",
    TRUE            ~ "ns"
  ))

# Calculate R^2 for each model and include class
rsquared_values <- purrr::imap(models, ~ {
  r2 <- r.squaredGLMM(.x)  # Calculate R2
  tibble(
    class = .y,            # Add class name (model name or identifier)
    R2m = r2[1],           # Marginal R2
    R2c = r2[2]            # Conditional R2
  )
}) %>% bind_rows()  # Combine the list of tibbles into a single data frame

# Print the resulting data frame
print(rsquared_values)


print(rsquared_values)

# Reshape to make features (terms) rows and classes columns
significance_table <- fixed_effects %>%
  dplyr::select(class, term, significance) %>%
  pivot_wider(names_from = class, values_from = significance, values_fill = "ns")

rsquared_rows <- rsquared_values %>%
  pivot_longer(cols = starts_with("R"), names_to = "term", values_to = "value") %>%
  mutate(term = case_when(
    term == "R2m" ~ "Marginal R²",
    term == "R2c" ~ "Conditional R²"
  )) %>%
  pivot_wider(names_from = class, values_from = value, names_prefix = "class") %>%
  mutate(across(-term, as.character))  # Ensure compatibility with `significance

rsquared_rows <- rsquared_rows %>%
  mutate(across(starts_with("class"), ~ as.character(.)))

rsquared_rows_clean <- rsquared_rows %>%
  rename_with(~ sub("^class", "", .), starts_with("class"))

# Then you can continue your pipeline with the cleaned data
combined_table <- bind_rows(significance_table, rsquared_rows_clean)

participant_counts <- tibble(
  term  = "# of Participants",
  class1 = "17", 
  class2 = "14", 
  class3 = "21", 
  class4 = "35", 
  class5 = "11"
)

# Append the participant counts to your original table
final_table <- bind_rows(combined_table, participant_counts)

# Print the updated table
print(final_table)


final_table %>%
  mutate(across(
    starts_with("class"),
    ~ ifelse(term %in% c("Marginal R²", "Conditional R²", "# of Participants"), ., str_sub(., 1, 4))
  )) %>%
  mutate(across(
    starts_with("class"),
    ~ ifelse(term %in% c("Marginal R²", "Conditional R²"), as.numeric(.), .)
  )) %>%
  gt() %>%
  tab_header(
    title = "Significance of Predictors and R² Values Across Classes",
    subtitle = "Significance levels: *** (<0.001), ** (<0.01), * (<0.05), ns (not significant)"
  ) %>%
  data_color(
    columns = starts_with("class"),
    colors = scales::col_factor(
      palette = c("yellow", "orange", "red", "white"),
      domain = c("***", "**", "*", "ns")
    )
  ) %>%
  fmt_number(
    rows = term %in% c("Marginal R²", "Conditional R²"),
    decimals = 3
  ) %>%
  tab_style(
    style = cell_fill(color = "white"),
    locations = cells_body(rows = term %in% c("Marginal R²", "Conditional R²"))
  ) %>%
  tab_style(
    style = cell_text(color = "black"),
    locations = cells_body(rows = term %in% c("Marginal R²", "Conditional R²", "# of Participants"))
  ) %>%
  tab_style(
    style = cell_fill(color = "white"),
    locations = cells_body(rows = term %in% c("# of Participants"))
  )

library(writexl)

# Save the underlying final_table to Excel. We edited the table format and have that version in the paper (also with rounded values)
write_xlsx(final_table, path = "final_table.xlsx")
LS0tCnRpdGxlOiAiSXMgaXQgbXVzaWM/IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBQYXVsaW5lIExhcnJvdXktTWFlc3RyaSAoRXhwIDEtMykgJiBULiBBdGEgQXlkaW4gKEV4cCA0KQplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCiMjIyBFeHBlcmltZW50IDEKCkFuYWx5c2lzIG9mIHRoZSBNdXNpYyBkYXRhIGNvbGxlY3RlZCBpbiBTZXB0ZW1iZXIgMjAyMgoKRm9sbG93aW5nIHRoZSBwcmVyZWdpc3RyYXRpb246IExhcnJvdXktTWFlc3RyaSwgUC4sICYgV2FsZC1GdWhybWFubiwgTS4gKDIwMjIsIFNlcHRlbWJlciAxMikuCkRlZmluaXRpb24gb2YgbXVzaWM6IEVmZmVjdCBvZiBzZWxmLSB2cyBvdGhlcnMtcmVmZXJlbmNlIGluIHRoZSBpZGVudGlmaWNhdGlvbiBvZiBhdWRpdG9yeSBzdGltdWxpIGFzIG11c2ljIG9yIG5vdC4KUmV0cmlldmVkIGZyb20gb3NmLmlvL3NiMjRxCgpDbGVhciBhbmQgbG9hZApgYGB7cn0Kcm0obGlzdCA9IGxzKCkpCgojIFNldCB3b3JraW5nIGRpcmVjdG9yeQpzZXR3ZCgiL1VzZXJzL3AubGFycm91eS9EZXNrdG9wL011c2ljX29zZiIpCgoKIyBMb2FkIGxpYnJhcmllcwpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShkcGx5cikKbGlicmFyeShsbWU0KQpsaWJyYXJ5KGdsbTIpCmxpYnJhcnkoZXopCmxpYnJhcnkoc3RhdHMpCmxpYnJhcnkobG1lNCkKbGlicmFyeShsbWVyVGVzdCkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShnZ2NvcnJwbG90KQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShocmJydGhlbWVzKQpsaWJyYXJ5KHZpcmlkaXNMaXRlKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoYnJvb20ubWl4ZWQpCmxpYnJhcnkocGVyZm9ybWFuY2UpCmxpYnJhcnkob3JkaW5hbCkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoSG1pc2MpCmxpYnJhcnkobWNsdXN0KQpsaWJyYXJ5KE5iQ2x1c3QpCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KHZjZCkKbGlicmFyeShncmlkKQoKIyBTZWxlY3QgZGF0YQpBbGxkYXRhIDwtIHJlYWRfZXhjZWwoIkV4cF8xLnhsc3giLCBzaGVldCA9ICJSZWdfQW5hbHlzaXNfMSIpClNlbGZkYXRhIDwtIHN1YnNldChBbGxkYXRhLCBBbGxkYXRhJENvbmRpdGlvbiA9PSAic2VsZiIpCk90aGVyZGF0YSA8LSBzdWJzZXQoQWxsZGF0YSwgQWxsZGF0YSRDb25kaXRpb24gPT0gIm90aGVyIikKCmBgYAoKUmVzY2FsZSB0aGUgQ29uZmlkZW5jZSByYXRpbmdzKDAtMyBpbnN0ZWFkIG9mIDEtNCkgdG8gbWF0Y2ggdGhlIGludGVudGlvbiBhbmQgdGhlIG1ldGhvZHMKCmBgYHtyfQojIENyZWF0ZSBhIG5ldyBjb2x1bW4gJ2NvbmZpZGVuY2VfcmVzY2FsZWQnIHRoYXQgaXMgYSBjb3B5IG9mICdDb25maWRlbmNlJwpBbGxkYXRhJGNvbmZpZGVuY2VfcmVzY2FsZWQgPC0gQWxsZGF0YSRDb25maWRlbmNlCgojIFJlc2NhbGUgJ2NvbmZpZGVuY2VfcmVzY2FsZWQnIGZvciBhbGwgZGF0YQpBbGxkYXRhJGNvbmZpZGVuY2VfcmVzY2FsZWQ8LSBBbGxkYXRhJGNvbmZpZGVuY2VfcmVzY2FsZWQgLSAxCmBgYAoKQU5BTFlTSVMgMTogRWZmZWN0IG9mIENvbmRpdGlvbiAoc2VsZiB2ZXJzdXMgb3RoZXIpIG9uIHRoZSBjYXRlZ29yaXNhdGlvbiBvZiBzdGltdWxpCgpNaXhlZCBlZmZlY3RzIGxvZ2lzdGljIHJlZ3Jlc3Npb24gd2lsbCBiZSBhcHBsaWVkIHRvIHByZWRpY3QgdGhlIHJlc3BvbnNlIChpLmUuLCAiTXVzaWMiIG9yICJOb3QgbXVzaWMiKSBmcm9tIHRoZSBjb25kaXRpb24sIHdpdGggcmFuZG9tIGludGVyY2VwdHMgZm9yIHBhcnRpY2lwYW50cyBhbmQgc3RpbXVsaSBpdGVtcy4KCk5PVEUgdGhhdCB0aGUgc3ludGF4IGluIHRoZSByZWdpc3RyYXRpb24gaW5jbHVkZWQgdGhlICJhIHByaW9yaSIgY29uZGl0aW9uIGJ1dCBpcyBub3QgcHJlc2VudGVkIGluIHRoZSBwYXBlciAob25seSBtZW50aW9uZWQgYXMgYSBmb290bm90ZSkKUHJvcG9zZWQgdGVudGF0aXZlIHN5bnRheCAoaW4gdGhlIHJlZ2lzdHJhdGlvbik6IE11c2ljX2Fuc3dlciB+IGEgcHJpb3JpIGdyb3VwICsgQ29uZGl0aW9uICsgYSBwcmlvcmkgZ3JvdXA6Q29uZGl0aW9uICsgKDF8UGFydGljaXBhbnQpICsgKDF8U3RpbSkKCkNvZGUgdG8gY2hhbmdlIHRoZSBiYXNlbGluZSBvZiB0aGUgZmFjdG9ycyAoc2VsZikgZm9yIHRoZSBtb2RlbApgYGB7cn0KQWxsZGF0YSRDb25kaXRpb24gPC0gYXMuZmFjdG9yKEFsbGRhdGEkQ29uZGl0aW9uKQpBbGxkYXRhJENvbmRpdGlvbiA8LSByZWxldmVsKEFsbGRhdGEkQ29uZGl0aW9uLCByZWYgPSAic2VsZiIpCmBgYAoKTnVsbCBhbmQgc2ltcGxlc3QgbW9kZWwsIGluY2x1ZGluZyBvbmx5IENvbmRpdGlvbjoKYGBge3J9CkVmZmVjdF9udWxsIDwtIGdsbWVyKGRhdGEgPSBBbGxkYXRhLCBNdXNpY19hbnN3ZXIgfiAxICsgKDF8UGFydGljaXBhbnQpICsgKDF8U3RpbSksIGZhbWlseSA9IGJpbm9taWFsKQpzdW1tYXJ5KEVmZmVjdF9udWxsKQoKRWZmZWN0X2xvZyA8LSBnbG1lcihkYXRhID0gQWxsZGF0YSwgTXVzaWNfYW5zd2VyIH4gQ29uZGl0aW9uICsgKDF8UGFydGljaXBhbnQpICsgKDF8U3RpbSksIGZhbWlseSA9IGJpbm9taWFsKQpzdW1tYXJ5KEVmZmVjdF9sb2cpCgphbm92YShFZmZlY3RfbnVsbCxFZmZlY3RfbG9nKQpgYGAKCkRldGFpbHMgYWJvdXQgdGhlIGZ1bGwgbW9kZWwKYGBge3J9CnRpZHkgKEVmZmVjdF9sb2cpCnBlcmZvcm1hbmNlKEVmZmVjdF9sb2cpCmBgYApJQ0MgZm9yIHRoZSByYW5kb20gZWZmZWN0cyAoYWxsIHRvZ2V0aGVyIGFuZCBzZXBhcmF0ZWx5KQpgYGB7cn0KIyBJQ0MgY2FsY3VsYXRpb24gYnkgZ3JvdXAKaWNjX3Jlc3VsdHNfZ3JvdXAgPC0gcGVyZm9ybWFuY2U6OmljYyhFZmZlY3RfbG9nLCBieV9ncm91cCA9IFRSVUUpCnByaW50KGljY19yZXN1bHRzX2dyb3VwKQoKIyBJQ0MgY2FsY3VsYXRpb24gZm9yIGFsbCByYW5kb20KaWNjX3Jlc3VsdHNfYWxsIDwtIHBlcmZvcm1hbmNlOjppY2MoRWZmZWN0X2xvZywgYnlfZ3JvdXAgPSBGQUxTRSkKcHJpbnQoaWNjX3Jlc3VsdHNfYWxsKQpgYGAKQU5BTFlTSVMgMWJpczogRWZmZWN0IG9mIGNvbmRpdGlvbiAoQ29uZGl0aW9uOiBzZWxmIHZlcnN1cyBvdGhlcikgb24gdGhlIGNvbmZpZGVuY2UgcmF0aW5ncyAoY29uZmlkZW5jZSBhcyBvcmRpbmFsIHZhcmlhYmxlKQpgYGB7cn0KY29uZl9vcmRfciA8LSBtdXRhdGUoQWxsZGF0YSwgY29uZmlkZW5jZV9yZXNjYWxlZCA9IGZhY3Rvcihjb25maWRlbmNlX3Jlc2NhbGVkLCBsZXZlbHM9MDozLCBvcmRlcmVkPVRSVUUpKQpjb25mX29yZF9yIDwtIG11dGF0ZShBbGxkYXRhLCBDb25kaXRpb24gPSBmYWN0b3IoQ29uZGl0aW9uLCBvcmRlcmVkPUZBTFNFKSkKCiMgQ2hlY2sgdGhlIGNsYXNzIGFuZCBsZXZlbHMgb2YgdGhlICdDb25maWRlbmNlJyB2YXJpYWJsZQpjbGFzcyhjb25mX29yZF9yJGNvbmZpZGVuY2VfcmVzY2FsZWQpCmxldmVscyhjb25mX29yZF9yJGNvbmZpZGVuY2VfcmVzY2FsZWQpCgojIENvbnZlcnQgJ0NvbmZpZGVuY2UnIHRvIGZhY3RvciBpZiBpdCdzIG5vdCBhbHJlYWR5CmNvbmZfb3JkX3IkY29uZmlkZW5jZV9yZXNjYWxlZCA8LSBmYWN0b3IoY29uZl9vcmRfciRjb25maWRlbmNlX3Jlc2NhbGVkLCBvcmRlcmVkID0gVFJVRSkKCiMgQ2hlY2sgdGhlIGNsYXNzIGFuZCBsZXZlbHMgYWdhaW4KY2xhc3MoY29uZl9vcmRfciRjb25maWRlbmNlX3Jlc2NhbGVkKQpsZXZlbHMoY29uZl9vcmRfciRjb25maWRlbmNlX3Jlc2NhbGVkKQoKIyBGaXQgdGhlIENMTU0gbW9kZWwgd2l0aG91dCB0aGUgZWZmZWN0IG9mIENvbmRpdGlvbgpFZmZlY3RfQ29uZl9udWxsX3IgPC0gY2xtbShjb25maWRlbmNlX3Jlc2NhbGVkIH4gMSArICgxfFBhcnRpY2lwYW50KSArICgxfFN0aW0pLCBkYXRhID0gY29uZl9vcmRfciwgbGluayA9ICJwcm9iaXQiLCB0aHJlc2hvbGQgPSAiZXF1aWRpc3RhbnQiKQpzdW1tYXJ5KEVmZmVjdF9Db25mX251bGxfcikKCiMgRml0IHRoZSBDTE1NIG1vZGVsIHdpdGggdGhlIGVmZmVjdCBvZiBDb25kaXRpb24KbW9kZWxfY29uZl9vcmRfciA8LSBjbG1tKGNvbmZpZGVuY2VfcmVzY2FsZWQgfiBDb25kaXRpb24gKyAoMSB8IFBhcnRpY2lwYW50KSArICgxIHwgU3RpbSksIGRhdGEgPSBjb25mX29yZF9yLCBsaW5rID0gInByb2JpdCIsIHRocmVzaG9sZCA9ICJlcXVpZGlzdGFudCIpCnN1bW1hcnkobW9kZWxfY29uZl9vcmRfcikKCiMgQ29tcGFyaXNvbiBvZiB0aGUgbnVsbCBhbmQgZnVsbCBtb2RlbCBmb3IgY29uZmlkZW5jZQphbm92YShFZmZlY3RfQ29uZl9udWxsX3IsbW9kZWxfY29uZl9vcmRfcikKCiMgSUNDIGNhbGN1bGF0aW9uIGJ5IGdyb3VwIChpLmUuLCBlYWNoIHJhbmRvbSBlZmZlY3RzKSBmb3IgdGhlIE5VTEwgbW9kZWwgKHNpbmNlIHRoZSBmdWxsIG1vZGVsIGlzIG5vdCBiZXR0ZXIpCmljY19yZXN1bHRzX2dyb3VwIDwtIHBlcmZvcm1hbmNlOjppY2MoRWZmZWN0X0NvbmZfbnVsbF9yLCBieV9ncm91cCA9IFRSVUUpCnByaW50KGljY19yZXN1bHRzX2dyb3VwKQoKIyBJQ0MgY2FsY3VsYXRpb24gZm9yIGFsbCByYW5kb20gZWZmZWN0cyB0b2dldGhlciBmb3IgdGhlIE5VTEwgbW9kZWwgKHNpbmNlIHRoZSBmdWxsIG1vZGVsIGlzIG5vdCBiZXR0ZXIpCmljY19yZXN1bHRzX2FsbCA8LSBwZXJmb3JtYW5jZTo6aWNjKEVmZmVjdF9Db25mX251bGxfciwgYnlfZ3JvdXAgPSBGQUxTRSkKcHJpbnQoaWNjX3Jlc3VsdHNfYWxsKQoKYGBgCgojIyMgRmlndXJlIDFBCgpgYGB7cn0KIyBDb21wdXRlIG1lYW4gbXVzaWMgcmVzcG9uc2VzIGFuZCBtZWFuIGNvbmZpZGVuY2UgcmF0aW5ncwpEYXRhUGxvdCA8LSB3aXRoKEFsbGRhdGEsIGFnZ3JlZ2F0ZShjYmluZChNdXNpY19hbnN3ZXIsIGNvbmZpZGVuY2VfcmVzY2FsZWQpLCBsaXN0KFN0aW11bGk9U3RpbSwgQ29uZGl0aW9uID0gQ29uZGl0aW9uKSwgbWVhbikpCkRhdGFQbG90CmBgYAoKClNldHRpbmcgY29sb3JzIGZvciB0aGUgcGxvdHMKCmBgYHtyfQoKc2VsZiA9ICJvcmFuZ2UiCm90aGVyID0gInB1cnBsZSIKCkNvbmRpdGlvbl9jb2xvcnMgPSBjKHNlbGYsb3RoZXIpCmBgYAoKClBsb3R0aW5nIHRoZSBtdXNpYyBhbnN3ZXJzIHdpdGggMiBjb250cmFzdGVkIGNvbG9ycyAoQ29uZGl0aW9uczogMXN0IGFuZCAzcmQgcGVyc29uLCBhbHNvIG5hbWVzIFNlbGYgYW5kIE90aGVyIGNvbmRpdGlvbnMpLCB3aXRoIG9yZGVyIGFjY29yZGluZyB0byB0aGUgU2VsZiB2YWx1ZXMKCmBgYHtyfQojIENhbGN1bGF0ZSB0aGUgbWVhbiBNdXNpY19hbnN3ZXIgZm9yIGVhY2ggc3RpbXVsdXMgaW4gdGhlICJzZWxmIiBjb25kaXRpb24Kc2VsZl9tZWFucyA8LSB3aXRoKHN1YnNldChBbGxkYXRhLCBDb25kaXRpb24gPT0gInNlbGYiKSwgCiAgICAgICAgICAgICAgICAgICB0YXBwbHkoTXVzaWNfYW5zd2VyLCBTdGltLCBtZWFuLCBuYS5ybSA9IFRSVUUpKQoKIyBFbnN1cmUgdGhlIE11c2ljX2Fuc3dlciBjb2x1bW4gaXMgbnVtZXJpYwpEYXRhUGxvdCRNdXNpY19hbnN3ZXIgPC0gYXMubnVtZXJpYyhEYXRhUGxvdCRNdXNpY19hbnN3ZXIpCgojIFJlb3JkZXIgdGhlIFN0aW11bGkgZmFjdG9yIGxldmVscyBiYXNlZCBvbiB0aGUgbWVhbnMgaW4gdGhlICJzZWxmIiBjb25kaXRpb24KRGF0YVBsb3QkU3RpbXVsaSA8LSBmYWN0b3IoRGF0YVBsb3QkU3RpbXVsaSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG5hbWVzKHNvcnQoc2VsZl9tZWFucywgZGVjcmVhc2luZyA9IEZBTFNFKSkpCgojIFJlb3JkZXIgdGhlIGxldmVscyBvZiB0aGUgQ29uZGl0aW9uIGZhY3RvcgpEYXRhUGxvdCRDb25kaXRpb24gPC0gZmFjdG9yKERhdGFQbG90JENvbmRpdGlvbiwgbGV2ZWxzID0gYygic2VsZiIsICJvdGhlciIpKQoKUmVzcG9uc2VQbG90IDwtIGdncGxvdChEYXRhUGxvdCwgYWVzKHggPSByZW9yZGVyKFN0aW11bGksIE11c2ljX2Fuc3dlciksIHkgPSBNdXNpY19hbnN3ZXIsIGdyb3VwID0gQ29uZGl0aW9uLCBjb2xvdXIgPSBDb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBDb25kaXRpb24pLCBzaXplID0gMy41KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBDb25kaXRpb25fY29sb3JzLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjFzdCBwZXJzb24iLCAiM3JkIHBlcnNvbiIpKSArICAjIFJlbmFtZSBDb25kaXRpb24gbGFiZWxzCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoInNlbGYiID0gMTYsICAgIyBTb2xpZCBjaXJjbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAib3RoZXIiID0gMSksICAgIyBIb2xsb3cgY2lyY2xlCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjFzdCBwZXJzb24iLCAiM3JkIHBlcnNvbiIpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB4bGFiKCJTdGltdWxpIChuID0gOTApIikgKwogIHlsYWIoIk11c2ljIHJlc3BvbnNlcyIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LCAwLjQpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKSAgIyBFbnN1cmUgd2hpdGUgYmFja2dyb3VuZAoKUmVzcG9uc2VQbG90CgpgYGAKClBsb3R0aW5nIENvbmZpZGVuY2UgZm9yIHNlbGYgYW5kIG90aGVyIGNvbmRpdGlvbnMKCmBgYHtyfQojIFJlb3JkZXIgdGhlIFN0aW11bGkgZmFjdG9yIGxldmVscyBiYXNlZCBvbiB0aGUgbWVhbnMgaW4gdGhlICJzZWxmIiBjb25kaXRpb24KRGF0YVBsb3QkU3RpbXVsaSA8LSBmYWN0b3IoRGF0YVBsb3QkU3RpbXVsaSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG5hbWVzKHNvcnQoc2VsZl9tZWFucywgZGVjcmVhc2luZyA9IEZBTFNFKSkpCgojIFJlb3JkZXIgdGhlIGxldmVscyBvZiB0aGUgQ29uZGl0aW9uIGZhY3RvcgpEYXRhUGxvdCRDb25kaXRpb24gPC0gZmFjdG9yKERhdGFQbG90JENvbmRpdGlvbiwgbGV2ZWxzID0gYygic2VsZiIsICJvdGhlciIpKQoKUmVzcG9uc2VQbG90X2NvbmYgPC0gZ2dwbG90KERhdGFQbG90LCBhZXMoeCA9IHJlb3JkZXIoU3RpbXVsaSwgTXVzaWNfYW5zd2VyKSwgeSA9IGNvbmZpZGVuY2VfcmVzY2FsZWQsIGdyb3VwID0gQ29uZGl0aW9uLCBjb2xvdXIgPSBDb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBDb25kaXRpb24pLCBzaXplID0gMy41KSArICAjIEFkanVzdCBzaXplIGZvciBjaXJjbGVzCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBDb25kaXRpb25fY29sb3JzLCAKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjFzdCBwZXJzb24iLCAiM3JkIHBlcnNvbiIpKSArICAjIFJlbmFtZSBDb25kaXRpb24gbGFiZWxzCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoInNlbGYiID0gMTYsICAgIyBTb2xpZCBjaXJjbGUgZm9yICJzZWxmIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvdGhlciIgPSAxKSwgICAjIEhvbGxvdyBjaXJjbGUgZm9yICJvdGhlciIKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMXN0IHBlcnNvbiIsICIzcmQgcGVyc29uIikpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHhsYWIoIlN0aW11bGkgKG4gPSA5MCkiKSArCiAgeWxhYigiQ29uZmlkZW5jZSIpICsKICB5bGltKDEuMywgMykgKyAgIyBBZGp1c3QgeS1heGlzIGxpbWl0cyBhcyBuZWVkZWQKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgIyBDaGFuZ2UgbGVnZW5kIHRleHQgZm9udCBzaXplCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksICMgQ2hhbmdlIGxlZ2VuZCB0aXRsZSBmb250IHNpemUKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsICAjIFJlbW92ZSB0aGUgbGVnZW5kCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkKClJlc3BvbnNlUGxvdF9jb25mCgoKYGBgCgpDb21iaW5lIHBsb3RzIElkZW50aWZpY2F0aW9uL0NvbmZpZGVuY2UgYW5kIHNhdmUKYGBge3J9CgpGaWd1cmVfMSA8LSBncmlkLmFycmFuZ2UoUmVzcG9uc2VQbG90LFJlc3BvbnNlUGxvdF9jb25mLG5jb2wgPSAxKQpnZ3NhdmUoIn4vRGVza3RvcC9SZXNwb25zZVBsb3RfZXhwMS50aWZmIiwgcGxvdCA9IEZpZ3VyZV8xLCB3aWR0aCA9IDUsIGhlaWdodCA9IDUsIGRwaSA9IDYwMCwgZGV2aWNlID0gInRpZmYiLCBjb21wcmVzc2lvbiA9ICJsenciKQoKYGBgCgojIyMgRXhwZXJpbWVudCAyCgpBbmFseXNpcyBvZiB0aGUgTXVzaWMgZGF0YSBjb2xsZWN0ZWQgaW4gTm92ZW1iZXIgMjAyMgoKRm9sbG93aW5nIHRoZSBwcmVyZWdpc3RyYXRpb246IExhcnJvdXktTWFlc3RyaSwgUC4sICYgV2FsZC1GdWhybWFubiwgTS4gKDIwMjIsIE5vdmVtYmVyIDIxKS4KUGVyY2VwdGlvbiBvZiBzb3VuZHMgYXMgbXVzaWMgb3Igbm90OiBlZmZlY3Qgb2Ygc3RpbXVsdXMgZHVyYXRpb24KUmV0cmlldmVkIGZyb20gb3NmLmlvL2F6a2NwCgpDbGVhciBhbmQgbG9hZAoKYGBge3J9CnJtKGxpc3QgPSBscygpKQoKIyBTZXQgd29ya2luZyBkaXJlY3RvcnkKc2V0d2QoIi9Vc2Vycy9wLmxhcnJvdXkvRGVza3RvcC9NdXNpY19vc2YiKQoKIyBMb2FkIGRhdGEKQWxsZGF0YSA8LSByZWFkX2V4Y2VsKCJFeHBfMi54bHN4Iiwgc2hlZXQgPSAiQ2F0ZWdvcmlzYXRpb25fdG9fYW5hbHlzZSIpCmRhdGEyPC0gc3Vic2V0KEFsbGRhdGEsIEFsbGRhdGEkRHVyYXRpb24gPT0gIjIiKQpkYXRhNSA8LSBzdWJzZXQoQWxsZGF0YSwgQWxsZGF0YSREdXJhdGlvbiA9PSAiNSIpCmRhdGExMCA8LSBzdWJzZXQoQWxsZGF0YSwgQWxsZGF0YSREdXJhdGlvbiA9PSAiMTAiKQoKYV9wcmlvcmlfZXhwMSA8LWFzLm51bWVyaWMoQWxsZGF0YSRhX3ByaW9yaV9leHAxX2xhYmVsKQpEdXJhdGlvbiA8LWFzLmZhY3RvcihBbGxkYXRhJER1cmF0aW9uKQoKYGBgCgoKUmVzY2FsZSB0aGUgQ29uZmlkZW5jZSByYXRpbmdzIGZvciBkdXJhdGlvbiBzaG9ydCBhbmQgbG9uZyAoMC0zIGluc3RlYWQgb2YgMS00KSB0byBtYXRjaCB0aGUgaW50ZW50aW9uLCB0aGUgbWV0aG9kcywgYW5kIHRoZSBkYXRlIG9mIHRoZSBtZWRpdW0gZHVyYXRpb24gKGkuZS4sIGRhdGEgb2YgRXhwMSwgc2VsZikKCmBgYHtyfQojIENyZWF0ZSBhIG5ldyBjb2x1bW4gJ2NvbmZpZGVuY2VfcmVzY2FsZWQnIHRoYXQgaXMgYSBjb3B5IG9mICdjb25maWRlbmNlJwpBbGxkYXRhJGNvbmZpZGVuY2VfcmVzY2FsZWQgPC0gQWxsZGF0YSRjb25maWRlbmNlCgojIFJlc2NhbGUgJ2NvbmZpZGVuY2VfcmVzY2FsZWQnIGZvciBEdXJhdGlvbiB2YWx1ZXMgMiBhbmQgOQpBbGxkYXRhJGNvbmZpZGVuY2VfcmVzY2FsZWRbQWxsZGF0YSREdXJhdGlvbl9sYWJlbCAlaW4lIGMoInNob3J0IiwgImxvbmciKV0gPC0gQWxsZGF0YSRjb25maWRlbmNlX3Jlc2NhbGVkW0FsbGRhdGEkRHVyYXRpb25fbGFiZWwgJWluJSBjKCJzaG9ydCIsICJsb25nIildIC0gMQoKIyBPcHRpb25hbDogVmVyaWZ5IHRoZSBjaGFuZ2VzCiMgWW91IGNhbiBjaGVjayBhIHN1YnNldCBvZiB0aGUgZGF0YSB0byBlbnN1cmUgdGhlIGNoYW5nZXMgYXJlIGNvcnJlY3QKaGVhZChBbGxkYXRhW0FsbGRhdGEkRHVyYXRpb25fbGFiZWwgJWluJSBjKCJzaG9ydCIsICJsb25nIiksIGMoIkR1cmF0aW9uX2xhYmVsIiwgImNvbmZpZGVuY2UiLCAiY29uZmlkZW5jZV9yZXNjYWxlZCIpXSkKCmBgYAoKQU5BTFlTSVMgMTogRWZmZWN0IG9mIGR1cmF0aW9uICgyIHZlcnN1cyA1IHZlcnN1cyAxMCkgb24gdGhlIGNhdGVnb3Jpc2F0aW9uIG9mIHN0aW11bGkKCk1peGVkIGVmZmVjdHMgbG9naXN0aWMgcmVncmVzc2lvbiB3aWxsIGJlIGFwcGxpZWQgdG8gcHJlZGljdCB0aGUgcmVzcG9uc2UgKGkuZS4sICJNdXNpYyIgb3IgIk5vdCBtdXNpYyIpIGZyb20gdGhlIGNvbmRpdGlvbiAoaS5lLiwgZHVyYXRpb246IDIsIDUsIDEwIHNlY29uZHMpLCB3aXRoIHJhbmRvbSBpbnRlcmNlcHRzIGZvciBwYXJ0aWNpcGFudHMgYW5kIHN0aW11bGkgaXRlbXMuCgpOT1RFIHRoYXQgd2UgZG9uJ3QgdXNlIHRoZSByZXN1bHRzIG9mIEV4cDEgKDMgZ3JvdXBzOm11c2ljLCBub19tdXNpYywgYW1iaWd1b3VzKSBzaW5jZSB3ZSByZXVzZSB0aGUgZGF0YSBvZiB0aGUgInNlbGYiIGdyb3VwIGZyb20gd2hpY2ggdGhlIHRocmVlIGdyb3VwcyB3ZXJlIGRlZmluZWQKCk5PVEUgdGhhdCB0aGUgc3ludGF4IGluIHRoZSByZWdpc3RyYXRpb24gaW5jbHVkZWQgdGhlICJhIHByaW9yaSIgY29uZGl0aW9uIGJ1dCBpcyBub3QgcHJlc2VudGVkIGluIHRoZSBwYXBlciAob25seSBtZW50aW9uZWQgYXMgYSBmb290bm90ZSkKUHJvcG9zZWQgdGVudGF0aXZlIHN5bnRheCAoaW4gdGhlIHJlZ2lzdHJhdGlvbik6IE11c2ljX2Fuc3dlciB+IGEgcHJpb3JpIGdyb3VwICsgRHVyYXRpb24gKyBhIHByaW9yaSBncm91cDpEdXJhdGlvbiArICgxfGV4cF9zdWJqZWN0X2lkKSArICgxfHN0aW1fbmFtZSkKCgpDb2RlIHRvIGNoYW5nZSB0aGUgYmFzZWxpbmUgb2YgdGhlIGZhY3RvcnMgKER1cmF0aW9uX2xhYmVsKSBmb3IgdGhlIG1vZGVsCmBgYHtyfQpBbGxkYXRhJER1cmF0aW9uX2xhYmVsIDwtIGFzLmZhY3RvcihBbGxkYXRhJER1cmF0aW9uX2xhYmVsKQpBbGxkYXRhJER1cmF0aW9uX2xhYmVsIDwtIHJlbGV2ZWwoQWxsZGF0YSREdXJhdGlvbl9sYWJlbCwgcmVmID0gIm1lZGl1bSIpCmBgYAoKTnVsbCBhbmQgc2ltcGxlc3QgbW9kZWwsIGluY2x1ZGluZyBvbmx5IGR1cmF0aW9uOgpgYGB7cn0KRWZmZWN0X251bGwgPC0gZ2xtZXIoZGF0YSA9IEFsbGRhdGEsIE11c2ljX2Fuc3dlciB+IDEgKyAoMXxleHBfc3ViamVjdF9pZCkgKyAoMXxzdGltX25hbWUpLCBmYW1pbHkgPSBiaW5vbWlhbCkKc3VtbWFyeShFZmZlY3RfbnVsbCkKCkVmZmVjdF9sb2cgPC0gZ2xtZXIoZGF0YSA9IEFsbGRhdGEsIE11c2ljX2Fuc3dlciB+IER1cmF0aW9uX2xhYmVsICsgKDF8ZXhwX3N1YmplY3RfaWQpICsgKDF8c3RpbV9uYW1lKSwgZmFtaWx5ID0gYmlub21pYWwpCnN1bW1hcnkoRWZmZWN0X2xvZykKCmFub3ZhKEVmZmVjdF9udWxsLEVmZmVjdF9sb2cpCmBgYAoKRGV0YWlscyBhYm91dCB0aGUgZnVsbCBtb2RlbApgYGB7cn0KdGlkeSAoRWZmZWN0X2xvZykKcGVyZm9ybWFuY2UoRWZmZWN0X2xvZykKYGBgCklDQyBmb3IgdGhlIHJhbmRvbSBlZmZlY3RzIChhbGwgdG9nZXRoZXIgYW5kIHNlcGFyYXRlbHkpCmBgYHtyfQojIElDQyBjYWxjdWxhdGlvbiBieSBncm91cAppY2NfcmVzdWx0c19ncm91cCA8LSBwZXJmb3JtYW5jZTo6aWNjKEVmZmVjdF9sb2csIGJ5X2dyb3VwID0gVFJVRSkKcHJpbnQoaWNjX3Jlc3VsdHNfZ3JvdXApCgojIElDQyBjYWxjdWxhdGlvbiBmb3IgYWxsIHJhbmRvbQppY2NfcmVzdWx0c19hbGwgPC0gcGVyZm9ybWFuY2U6OmljYyhFZmZlY3RfbG9nLCBieV9ncm91cCA9IEZBTFNFKQpwcmludChpY2NfcmVzdWx0c19hbGwpCmBgYAoKQU5BTFlTSVMgMWJpczogRWZmZWN0IG9mIGNvbmRpdGlvbiAoZHVyYXRpb246IHNob3J0LCBtZWRpdW0sIGxvbmcpIG9uIHRoZSBjb25maWRlbmNlIHJhdGluZ3MgKGNvbmZpZGVuY2UgYXMgb3JkaW5hbCB2YXJpYWJsZSkKYGBge3J9CmNvbmZfb3JkX3IgPC0gbXV0YXRlKEFsbGRhdGEsIGNvbmZpZGVuY2VfcmVzY2FsZWQgPSBmYWN0b3IoY29uZmlkZW5jZV9yZXNjYWxlZCwgbGV2ZWxzPTA6Mywgb3JkZXJlZD1UUlVFKSkKY29uZl9vcmRfciA8LSBtdXRhdGUoQWxsZGF0YSwgQ29uZGl0aW9uID0gZmFjdG9yKER1cmF0aW9uX2xhYmVsLCBvcmRlcmVkPUZBTFNFKSkKCiMgQ2hlY2sgdGhlIGNsYXNzIGFuZCBsZXZlbHMgb2YgdGhlICdDb25maWRlbmNlJyB2YXJpYWJsZQpjbGFzcyhjb25mX29yZF9yJGNvbmZpZGVuY2VfcmVzY2FsZWQpCmxldmVscyhjb25mX29yZF9yJGNvbmZpZGVuY2VfcmVzY2FsZWQpCgojIENvbnZlcnQgJ0NvbmZpZGVuY2UnIHRvIGZhY3RvciBpZiBpdCdzIG5vdCBhbHJlYWR5CmNvbmZfb3JkX3IkY29uZmlkZW5jZV9yZXNjYWxlZCA8LSBmYWN0b3IoY29uZl9vcmRfciRjb25maWRlbmNlX3Jlc2NhbGVkLCBvcmRlcmVkID0gVFJVRSkKCiMgQ2hlY2sgdGhlIGNsYXNzIGFuZCBsZXZlbHMgYWdhaW4KY2xhc3MoY29uZl9vcmRfciRjb25maWRlbmNlX3Jlc2NhbGVkKQpsZXZlbHMoY29uZl9vcmRfciRjb25maWRlbmNlX3Jlc2NhbGVkKQoKIyBGaXQgdGhlIENMTU0gbW9kZWwgd2l0aG91dCB0aGUgZWZmZWN0IG9mIENvbmRpdGlvbgpFZmZlY3RfQ29uZl9udWxsX3IgPC0gY2xtbShjb25maWRlbmNlX3Jlc2NhbGVkIH4gMSArICgxfGV4cF9zdWJqZWN0X2lkKSArICgxfHN0aW1fbmFtZSksIGRhdGEgPSBjb25mX29yZF9yLCBsaW5rID0gInByb2JpdCIsIHRocmVzaG9sZCA9ICJlcXVpZGlzdGFudCIpCnN1bW1hcnkoRWZmZWN0X0NvbmZfbnVsbF9yKQoKIyBGaXQgdGhlIENMTU0gbW9kZWwgd2l0aCB0aGUgZWZmZWN0IG9mIENvbmRpdGlvbgptb2RlbF9jb25mX29yZF9yIDwtIGNsbW0oY29uZmlkZW5jZV9yZXNjYWxlZCB+IER1cmF0aW9uX2xhYmVsICsgKDEgfCBleHBfc3ViamVjdF9pZCkgKyAoMSB8IHN0aW1fbmFtZSksIGRhdGEgPSBjb25mX29yZF9yLCBsaW5rID0gInByb2JpdCIsIHRocmVzaG9sZCA9ICJlcXVpZGlzdGFudCIpCnN1bW1hcnkobW9kZWxfY29uZl9vcmRfcikKCiMgQ29tcGFyaXNvbiBvZiB0aGUgbnVsbCBhbmQgZnVsbCBtb2RlbCBmb3IgY29uZmlkZW5jZQphbm92YShFZmZlY3RfQ29uZl9udWxsX3IsbW9kZWxfY29uZl9vcmRfcikKCiMgSUNDIGNhbGN1bGF0aW9uIGJ5IGdyb3VwIChpLmUuLCBlYWNoIHJhbmRvbSBlZmZlY3RzKSBmb3IgdGhlIE5VTEwgbW9kZWwgKHNpbmNlIHRoZSBmdWxsIG1vZGVsIGlzIG5vdCBiZXR0ZXIpCmljY19yZXN1bHRzX2dyb3VwIDwtIHBlcmZvcm1hbmNlOjppY2MoRWZmZWN0X0NvbmZfbnVsbF9yLCBieV9ncm91cCA9IFRSVUUpCnByaW50KGljY19yZXN1bHRzX2dyb3VwKQoKIyBJQ0MgY2FsY3VsYXRpb24gZm9yIGFsbCByYW5kb20gZWZmZWN0cyB0b2dldGhlciBmb3IgdGhlIE5VTEwgbW9kZWwgKHNpbmNlIHRoZSBmdWxsIG1vZGVsIGlzIG5vdCBiZXR0ZXIpCmljY19yZXN1bHRzX2FsbCA8LSBwZXJmb3JtYW5jZTo6aWNjKEVmZmVjdF9Db25mX251bGxfciwgYnlfZ3JvdXAgPSBGQUxTRSkKcHJpbnQoaWNjX3Jlc3VsdHNfYWxsKQoKYGBgCgoKIyMjIEZpZ3VyZSAxQgoKYGBge3J9CiMgQ29tcHV0ZSBtZWFuIG11c2ljIHJlc3BvbnNlcyBhbmQgbWVhbiBjb25maWRlbmNlIHJhdGluZ3MKRGF0YVBsb3QgPC0gd2l0aChBbGxkYXRhLCBhZ2dyZWdhdGUoTXVzaWNfYW5zd2VyLCBsaXN0KFN0aW11bGk9c3RpbV9uYW1lLENvbmRpdGlvbj1EdXJhdGlvbl9sYWJlbCksIG1lYW4pKQpgYGAKClNldHRpbmcgY29sb3JzIGZvciB0aGUgcGxvdHMKCmBgYHtyfQpzID0gImdvbGQiCm0gPSAib3JhbmdlIgpsID0gImJyb3duIgoKZHVyX2NvbG9ycyA9IGMocyxtLGwpCmBgYAoKUGxvdHRpbmcgdGhlIG11c2ljIGFuc3dlcnMgd2l0aCAzIGNvbG9ycyAoQ29uZGl0aW9uczogU2hvcnQsIE1lZGl1bSwgYW5kIExvbmcgc3RpbXVsaSkKYGBge3J9CkRhdGFQbG90IDwtIHdpdGgoQWxsZGF0YSwgYWdncmVnYXRlKE11c2ljX2Fuc3dlciwgbGlzdChTdGltdWxpPXN0aW1fbmFtZSxDb25kaXRpb249RHVyYXRpb25fbGFiZWwpLCBtZWFuKSkKCiMgUmVvcmRlciB0aGUgbGV2ZWxzIG9mIHRoZSBDb25kaXRpb24gZmFjdG9yCkRhdGFQbG90JENvbmRpdGlvbiA8LSBmYWN0b3IoRGF0YVBsb3QkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJzaG9ydCIsICJtZWRpdW0iLCAibG9uZyIpKQoKIyBDcmVhdGUgdGhlIHBsb3Qgd2l0aCB0aGUgcmVvcmRlcmVkIENvbmRpdGlvbiBsZXZlbHMKUmVzcG9uc2VQbG90IDwtIGdncGxvdChEYXRhUGxvdCwgYWVzKHggPSByZW9yZGVyKFN0aW11bGksIHgpLCB5ID0geCwgZ3JvdXAgPSBDb25kaXRpb24sIGNvbG91ciA9IENvbmRpdGlvbikpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IENvbmRpdGlvbiksIHNpemUgPSAzLjUpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGR1cl9jb2xvcnMsCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJTaG9ydCIsICJNZWRpdW0iLCAiTG9uZyIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoInNob3J0IiA9IDEsICAgIyBTb2xpZCBjaXJjbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1lZGl1bSIgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxvbmciPSAxKSwgICAjIEhvbGxvdyBjaXJjbGUKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiU2hvcnQiLCAiTWVkaXVtIiwgIkxvbmciKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgeGxhYigiU3RpbXVsaSAobiA9IDc1KSIpICsKICB5bGFiKCJNdXNpYyByZXNwb25zZXMiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCAKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwgMC40KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKwogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKQoKUmVzcG9uc2VQbG90CgpgYGAKClBsb3R0aW5nIENvbmZpZGVuY2UgZm9yIFNob3J0LCBNZWRpdW0sIGFuZCBMb25nIHN0aW11bGkKCmBgYHtyfQojIENvbXB1dGUgbWVhbiBtdXNpYyByZXNwb25zZXMgYW5kIG1lYW4gY29uZmlkZW5jZSByYXRpbmdzCkRhdGFQbG90IDwtIHdpdGgoQWxsZGF0YSwgYWdncmVnYXRlKGNiaW5kKE11c2ljX2Fuc3dlciwgY29uZmlkZW5jZV9yZXNjYWxlZCksIGxpc3QoU3RpbXVsaT1zdGltX25hbWUsIENvbmRpdGlvbiA9IER1cmF0aW9uX2xhYmVsKSwgbWVhbikpCkRhdGFQbG90CgojIFJlb3JkZXIgdGhlIGxldmVscyBvZiB0aGUgQ29uZGl0aW9uIGZhY3RvcgpEYXRhUGxvdCRDb25kaXRpb24gPC0gZmFjdG9yKERhdGFQbG90JENvbmRpdGlvbiwgbGV2ZWxzID0gYygic2hvcnQiLCAibWVkaXVtIiwgImxvbmciKSkKCiMgUGxvdCBjb25maWRlbmNlIGxpa2UgZm9yIGlkZW50aWZpY2F0aW9uClJlc3BvbnNlUGxvdF9jb25mIDwtIGdncGxvdChEYXRhUGxvdCwgYWVzKHggPSByZW9yZGVyKFN0aW11bGksIE11c2ljX2Fuc3dlciksIHkgPSBjb25maWRlbmNlX3Jlc2NhbGVkLCBncm91cCA9IENvbmRpdGlvbiwgY29sb3VyID0gQ29uZGl0aW9uKSkgKwogIGdlb21fcG9pbnQoYWVzKHNoYXBlID0gQ29uZGl0aW9uKSwgc2l6ZSA9IDMuNSkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gZHVyX2NvbG9ycywKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlNob3J0IiwgIk1lZGl1bSIsICJMb25nIikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygic2hvcnQiID0gMSwgICAjIEhvbGxvdyBjaXJjbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1lZGl1bSIgPSAxNiwgIyBTb2xpZCBjaXJjbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxvbmciPSAxKSwgICAjIEhvbGxvdyBjaXJjbGUKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiU2hvcnQiLCAiTWVkaXVtIiwgIkxvbmciKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgIyBzY2FsZV9zaGFwZShzb2xpZCA9IEZBTFNFKSArCiAgeGxhYigiU3RpbXVsaSAobiA9IDc1KSIpICsKICB5bGFiKCJDb25maWRlbmNlIikgKwogIHlsaW0oMS4zLCAzKSArICAjIEFkanVzdCB5LWF4aXMgbGltaXRzIGFzIG5lZWRlZAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLCAjIENoYW5nZSBsZWdlbmQgdGV4dCBmb250IHNpemUKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgIyBDaGFuZ2UgbGVnZW5kIHRpdGxlIGZvbnQgc2l6ZQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgICMgUmVtb3ZlIHRoZSBsZWdlbmQKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKwogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKQoKUmVzcG9uc2VQbG90X2NvbmYKCmBgYAoKQ29tYmluZSBwbG90cyBhbmQgc2F2ZQoKYGBge3J9CgpGaWd1cmVfMUIgPC0gZ3JpZC5hcnJhbmdlKFJlc3BvbnNlUGxvdCxSZXNwb25zZVBsb3RfY29uZixuY29sID0gMSkKZ2dzYXZlKCJ+L0Rlc2t0b3AvUmVzcG9uc2VQbG90X2V4cDIudGlmZiIsIHBsb3QgPSBGaWd1cmVfMUIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNSwgZHBpID0gNjAwLCBkZXZpY2UgPSAidGlmZiIsIGNvbXByZXNzaW9uID0gImx6dyIpCgpgYGAKCiMjIyBFeHBlcmltZW50IDMKCkFuYWx5c2lzIG9mIHRoZSBNdXNpYyBkYXRhIGNvbGxlY3RlZCBpbiBOb3ZlbWJlciAyMDIyCgpGb2xsb3dpbmcgdGhlIHByZXJlZ2lzdHJhdGlvbjogTGFycm91eS1NYWVzdHJpLCBQLiwgJiBXYWxkLUZ1aHJtYW5uLCBNLiAoMjAyMiwgTm92ZW1iZXIgMjEpLgpQZXJjZXB0aW9uIG9mIHNvdW5kcyBhcyBtdXNpYyBvciBub3Q6IGVmZmVjdCBvZiBzdGltdWx1cyBkdXJhdGlvbgpSZXRyaWV2ZWQgZnJvbSBvc2YuaW8vYXprY3AKCkNsZWFyIGFuZCBsb2FkCmBgYHtyfQpybShsaXN0ID0gbHMoKSkKCiMgU2V0IHdvcmtpbmcgZGlyZWN0b3J5CnNldHdkKCIvVXNlcnMvcC5sYXJyb3V5L0Rlc2t0b3AvTXVzaWNfb3NmIikKCiMgTG9hZCBkYXRhCkFsbGRhdGEgPC0gcmVhZF9leGNlbCgiRXhwXzMueGxzeCIsIHNoZWV0ID0gIkNhdGVnb3Jpc2F0aW9uX3RvX2FuYWx5c2UiKQoKU3RpbXVsdXMgPC0gYXMubnVtZXJpYyhBbGxkYXRhJHN0aW1fbmFtZSkKZXhwX3N1YmplY3RfaWQgPC1hcy5mYWN0b3IoQWxsZGF0YSRleHBfc3ViamVjdF9pZCkKCmBgYAoKQU5BTFlTSVMgMTogRWZmZWN0IG9mIHJlcGV0aXRpb24gb24gdGhlIGNhdGVnb3Jpc2F0aW9uIG9mIHN0aW11bGkKCk1peGVkIGVmZmVjdHMgbG9naXN0aWMgcmVncmVzc2lvbiB3aWxsIGJlIGFwcGxpZWQgdG8gcHJlZGljdCB0aGUgcmVzcG9uc2UgKGkuZS4sICJNdXNpYyIgb3IgIk5vdCBtdXNpYyIpIGZyb20gdGhlIGNvbmRpdGlvbiAoaS5lLiwgZmlyc3Qgb3Igc2Vjb25kIHByZXNlbnRhdGlvbiksIHdpdGggcmFuZG9tIGludGVyY2VwdHMgZm9yIHBhcnRpY2lwYW50cyBhbmQgc3RpbXVsaSBpdGVtcy4KCk5PVEUgdGhhdCB0aGUgc3ludGF4IGluIHRoZSByZWdpc3RyYXRpb24gaW5jbHVkZWQgdGhlICJhIHByaW9yaSIgY29uZGl0aW9uIGJ1dCBpcyBub3QgcHJlc2VudGVkIGluIHRoZSBwYXBlciAob25seSBtZW50aW9uZWQgYXMgYSBmb290bm90ZSkKUHJvcG9zZWQgdGVudGF0aXZlIHN5bnRheCAoaW4gdGhlIHJlZ2lzdHJhdGlvbik6IE11c2ljX2Fuc3dlciB+IGEgcHJpb3JpIGdyb3VwICsgT3JkZXIgKyBhIHByaW9yaSBncm91cDpPcmRlciArICgxfGV4cF9zdWJqZWN0X2lkKSArICgxfHN0aW1fbmFtZSkKCgpDb2RlIHRvIGNoYW5nZSB0aGUgYmFzZWxpbmUgb2YgdGhlIGZhY3RvcnMgKE9yZGVyX2xldHRlcikgZm9yIHRoZSBtb2RlbApgYGB7cn0KQWxsZGF0YSRPcmRlcl9sZXR0ZXIgPC0gYXMuZmFjdG9yKEFsbGRhdGEkT3JkZXJfbGV0dGVyKQpBbGxkYXRhJE9yZGVyX2xldHRlciA8LSByZWxldmVsKEFsbGRhdGEkT3JkZXJfbGV0dGVyLCByZWYgPSAidGVzdCIpCmBgYAoKTnVsbCBhbmQgc2ltcGxlc3QgbW9kZWwsIGluY2x1ZGluZyBvbmx5IGR1cmF0aW9uOgpgYGB7cn0KRWZmZWN0X251bGwgPC0gZ2xtZXIoZGF0YSA9IEFsbGRhdGEsIE11c2ljX2Fuc3dlciB+IDEgKyAoMXxleHBfc3ViamVjdF9pZCkgKyAoMXxzdGltX25hbWUpLCBmYW1pbHkgPSBiaW5vbWlhbCkKc3VtbWFyeShFZmZlY3RfbnVsbCkKCkVmZmVjdF9sb2cgPC0gZ2xtZXIoZGF0YSA9IEFsbGRhdGEsIE11c2ljX2Fuc3dlciB+IE9yZGVyX2xldHRlciArICgxfGV4cF9zdWJqZWN0X2lkKSArICgxfHN0aW1fbmFtZSksIGZhbWlseSA9IGJpbm9taWFsKQpzdW1tYXJ5KEVmZmVjdF9sb2cpCgphbm92YShFZmZlY3RfbnVsbCxFZmZlY3RfbG9nKQpgYGAKCkRldGFpbHMgYWJvdXQgdGhlIGZ1bGwgbW9kZWwKYGBge3J9CnRpZHkgKEVmZmVjdF9sb2cpCnBlcmZvcm1hbmNlKEVmZmVjdF9sb2cpCmBgYAoKSUNDIGZvciB0aGUgcmFuZG9tIGVmZmVjdHMgKGFsbCB0b2dldGhlciBhbmQgc2VwYXJhdGVseSkKYGBge3J9CiMgSUNDIGNhbGN1bGF0aW9uIGJ5IGdyb3VwCmljY19yZXN1bHRzX2dyb3VwIDwtIHBlcmZvcm1hbmNlOjppY2MoRWZmZWN0X2xvZywgYnlfZ3JvdXAgPSBUUlVFKQpwcmludChpY2NfcmVzdWx0c19ncm91cCkKCiMgSUNDIGNhbGN1bGF0aW9uIGZvciBhbGwgcmFuZG9tCmljY19yZXN1bHRzX2FsbCA8LSBwZXJmb3JtYW5jZTo6aWNjKEVmZmVjdF9sb2csIGJ5X2dyb3VwID0gRkFMU0UpCnByaW50KGljY19yZXN1bHRzX2FsbCkKYGBgCgojIEZpZ3VyZSAxQwoKUHJlcGFyYXRpb24gZm9yIHRoZSBmaWd1cmUgd2l0aCBlYWNoIHJldGVzdHMgKDMgY29uZGl0aW9ucykgYWdhaW5zdCB0aGUgYmFzZWxpbmUgKHNpbmdsZSBmb3IgYWxsICJ0ZXN0IikKYGBge3J9CgpBbGxkYXRhIDwtIEFsbGRhdGEgJT4lCiAgbXV0YXRlKE5ld19Hcm91cCA9IGNhc2Vfd2hlbigKICAgIE9yZGVyX2xldHRlciA9PSAndGVzdCcgIH4gJ0Jhc2VsaW5lJywKICAgIE9yZGVyX2xldHRlciA9PSAncmV0ZXN0JyAmIFBvc2l0aW9uID09ICdCQicgfiAnQkInLAogICAgT3JkZXJfbGV0dGVyID09ICdyZXRlc3QnICYgUG9zaXRpb24gPT0gJ1dCUicgfiAnV0JSJywKICAgIE9yZGVyX2xldHRlciA9PSAncmV0ZXN0JyAmIFBvc2l0aW9uID09ICdXQkMnIH4gJ1dCQycsCiAgICBUUlVFIH4gJ090aGVyJwogICkpCgpgYGAKCgpTZXR0aW5nIGNvbG9ycyBmb3IgdGhlIHBsb3RzCgpgYGB7cn0KYmFzZWxpbmUgPSAiZ3JleSIKQkIgPSAicGluayIKV0JSID0gImN5YW4iCldCQyA9ICJtYWdlbnRhIgoKUG9zaXRpb25fY29sb3JzID0gYyhiYXNlbGluZSxCQixXQlIsV0JDKQpgYGAKClBsb3R0aW5nIHRoZSBtdXNpYyBhbnN3ZXJzIHdpdGggMyBjb2xvcnMgKENvbmRpdGlvbnM6IEJhc2VsaW5lLCBCQiwgV0JDLCBXQlIpCmBgYHtyfQoKIyMgRnJvbSBleHAyOgogICMgQ29tcHV0ZSBtZWFuIG11c2ljIHJlc3BvbnNlcyBhbmQgbWVhbiBjb25maWRlbmNlIHJhdGluZ3MKRGF0YVBsb3QgPC0gd2l0aChBbGxkYXRhLCBhZ2dyZWdhdGUoTXVzaWNfYW5zd2VyLCBsaXN0KFN0aW11bGk9c3RpbV9uYW1lLENvbmRpdGlvbj1OZXdfR3JvdXApLCBtZWFuKSkKCkRhdGFQbG90CgpCYXNlbGluZV9tZWFucyA8LSB3aXRoKHN1YnNldChBbGxkYXRhLCBOZXdfR3JvdXAgPT0gIkJhc2VsaW5lIiksIAogICAgICAgICAgICAgICAgICAgdGFwcGx5KE11c2ljX2Fuc3dlciwgc3RpbV9uYW1lLCBtZWFuLCBuYS5ybSA9IFRSVUUpKQoKIyBSZW9yZGVyIHRoZSBTdGltdWxpIGZhY3RvciBsZXZlbHMgYmFzZWQgb24gdGhlIG1lYW5zIGluIHRoZSAic2VsZiIgY29uZGl0aW9uCkRhdGFQbG90JFN0aW11bGkgPC0gZmFjdG9yKERhdGFQbG90JFN0aW11bGksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBuYW1lcyhzb3J0KEJhc2VsaW5lX21lYW5zLCBkZWNyZWFzaW5nID0gRkFMU0UpKSkKCiMgUmVvcmRlciB0aGUgbGV2ZWxzIG9mIHRoZSBDb25kaXRpb24gZmFjdG9yCkRhdGFQbG90JENvbmRpdGlvbiA8LSBmYWN0b3IoRGF0YVBsb3QkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJCYXNlbGluZSIsICJCQiIsICJXQlIiLCJXQkMiKSkKCgojIENyZWF0ZSB0aGUgcGxvdCB3aXRoIHRoZSByZW9yZGVyZWQgQ29uZGl0aW9uIGxldmVscwpSZXNwb25zZVBsb3QgPC0gZ2dwbG90KERhdGFQbG90LCBhZXMoU3RpbXVsaSwgeSA9IHgsIGdyb3VwID0gQ29uZGl0aW9uLCBjb2xvdXIgPSBDb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBDb25kaXRpb24pLCBzaXplID0gMy41KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBQb3NpdGlvbl9jb2xvcnMsCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJCYXNlbGluZSIsICAiQkIiLCAiV0JSIiwiV0JDIikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygiQmFzZWxpbmUiID0gMTYsICAgIyBTb2xpZCBjaXJjbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJCIiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXQlIiPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV0JDIj0gMSksICAgIyBIb2xsb3cgY2lyY2xlCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkJhc2VsaW5lIiwgICJCQiIsICJXQlIiLCJXQkMiKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgeGxhYigiU3RpbXVsaSAobiA9IDQyKSIpICsKICB5bGFiKCJNdXNpYyByZXNwb25zZXMiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksIAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLCAKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuMjUsIDAuNyksICAjIE1vdmUgbGVnZW5kIHRvIHRvcC1sZWZ0CiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMC4xLCAiY20iKSkgKyAgIyBBZGp1c3Qgc3BhY2UgYmV0d2VlbiBsZWdlbmQgaXRlbXMKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkKUmVzcG9uc2VQbG90CgpgYGAKCkNyZWF0ZSBhbmQgZXhwb3J0IHBsb3QKYGBge3J9CkZpZ3VyZV8xQyA8LSBncmlkLmFycmFuZ2UoUmVzcG9uc2VQbG90LG5jb2wgPSAxKQpnZ3NhdmUoIn4vRGVza3RvcC9SZXNwb25zZVBsb3RfZXhwM2EudGlmZiIsIHBsb3QgPSBGaWd1cmVfMUMsIHdpZHRoID0gMywgaGVpZ2h0ID0gMiwgZHBpID0gNjAwLCBkZXZpY2UgPSAidGlmZiIsIGNvbXByZXNzaW9uID0gImx6dyIpCmBgYAoKTGlzdGVuZXJzJyBjb25zaXN0ZW5jZSBvYnNlcnZlZCB3aXRoIHRlc3QtcmV0ZXN0IHBoaS1jb2VmZmljaWVudHMgZm9yIGVhY2ggY29uZGl0aW9uCgpgYGB7cn0KY29uc2lzdF9zdWIgPC0gd2l0aChBbGxkYXRhLCBhZ2dyZWdhdGUoTXVzaWNfYW5zd2VyLCBsaXN0KFN1Yj1leHBfc3ViamVjdF9pZCwgU3RpbXVsaT1zdGltX25hbWUsUG9zaXRpb249UG9zaXRpb24sUmVwZXRpdGlvbj1PcmRlciksIG1lYW4pKQpjb25zaXN0X3N1YgoKY29uc2lzdGVuY3lfc3ViIDwtcmVzaGFwZShjb25zaXN0X3N1YiwgaWR2YXIgPWMoIlN0aW11bGkiLCAiUG9zaXRpb24iLCJTdWIiKSwgdGltZXZhciA9IGMoIlJlcGV0aXRpb24iKSwgZGlyZWN0aW9uID0gIndpZGUiKQpjb25zaXN0ZW5jeV9zdWIgCgpzdWJfY29ycmVsYXRpb24gPC0gY29uc2lzdGVuY3lfc3ViICU+JQogIGdyb3VwX2J5KFN1YiwgUG9zaXRpb24pICU+JQogIHN1bW1hcmlzZSgKICAgIHBoaV9jb2VmZmljaWVudCA9IHsKICAgICAgdGJsIDwtIHRhYmxlKHguMSwgeC4yKQogICAgICBhc3NvY3N0YXRzKHRibCkkcGhpCiAgICB9LAogICAgcF92YWx1ZSA9IHsKICAgICAgdGJsIDwtIHRhYmxlKHguMSwgeC4yKQogICAgICBjaGlzcS50ZXN0KHRibCkkcC52YWx1ZQogICAgfQogICkKCnByaW50KHN1Yl9jb3JyZWxhdGlvbikKYGBgCgpQbG90IGxpc3RlbmVycycgY29uc2lzdGVuY3kgYmV0d2VlbiBmaXJzdCBhbmQgc2Vjb25kIHByZXNlbnRhdGlvbiAoZ3JleSBkb3QgZm9yIGVhY2ggc3RpbXVsdXMgb24gYSB4IGF4aXMpIGZvciBlYWNoIFBvc2l0aW9uIHNlcGFyYXRlbHkgKHkgYXhpcykKCmBgYHtyfQojIFBsb3QgdGhlIGRpZmZlcmVuY2UgdmFsdWVzIGZvciBlYWNoIGdyb3VwIGluICdQb3NpdGlvbicKCiMgRnVuY3Rpb24gdG8gY2FsY3VsYXRlIG1lYW4gYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCm1lYW5fY2kgPC0gZnVuY3Rpb24oeCkgewogIG1lYW5feCA8LSBtZWFuKHgpCiAgY2kgPC0gcXQoMC45NzUsIGRmID0gbGVuZ3RoKHgpIC0gMSkgKiBzZCh4KSAvIHNxcnQobGVuZ3RoKHgpKQogIHJldHVybihkYXRhLmZyYW1lKHkgPSBtZWFuX3gsIHltaW4gPSBtZWFuX3ggLSBjaSwgeW1heCA9IG1lYW5feCArIGNpKSkKfQoKUG9zaXRpb25fY29sb3JzX3Zpb2xpbiA9IGMoQkIsV0JDLFdCUikKCiMgUGxvdCBpdHNlbGYKQ29uc2lzdGVuY3lQbG90IDwtIGdncGxvdChzdWJfY29ycmVsYXRpb24sIGFlcyh4ID0gUG9zaXRpb24sIHkgPSBwaGlfY29lZmZpY2llbnQsIGNvbG91ciA9IFBvc2l0aW9uLCBmaWxsID0gUG9zaXRpb24pKSArCiAgI2dlb21fdmlvbGluKGFscGhhID0gMC41KSArCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC41KSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IFBvc2l0aW9uX2NvbG9yc192aW9saW4pICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBQb3NpdGlvbl9jb2xvcnNfdmlvbGluKSArCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjIsIGFscGhhID0gMC41KSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jaSwgZ2VvbSA9ICJwb2ludHJhbmdlIiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC41KSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKCN0aXRsZSA9ICJFeHAgMyIsCiAgICAgICB4ID0gIlBvc2l0aW9uIiwKICAgICAgIHkgPSAiUGhpIGNvZWZpY2llbnQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJQb3NpdGlvbiIsCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkKCkNvbnNpc3RlbmN5UGxvdAoKYGBgCgpDcmVhdGlvbiBhbmQgZXhwb3J0IG9mIGZpZ3VyZSAxQwoKYGBge3J9CkZpZ3VyZV8xQyA8LSBncmlkLmFycmFuZ2UoUmVzcG9uc2VQbG90LENvbnNpc3RlbmN5UGxvdCxuY29sID0gMSkKZ2dzYXZlKCJ+L0Rlc2t0b3AvUmVzcG9uc2VQbG90X2V4cDMudGlmZiIsIHBsb3QgPSBGaWd1cmVfMUMsIHdpZHRoID0gMywgaGVpZ2h0ID0gNSwgZHBpID0gNjAwLCBkZXZpY2UgPSAidGlmZiIsIGNvbXByZXNzaW9uID0gImx6dyIpCmBgYAoKQ29tcGFyaXNvbiBvZiBsaXN0ZW5lcnMnIGNvbnNpc3RlbmN5IChpLmUuLCBQaGkgY29lZmZpY2llbnRzKSBhY3Jvc3MgY29uZGl0aW9ucyB3aXRoIGFub3ZhIGFuZCBUdXJrZXkgdGVzdAoKYGBge3J9CiMjIFRlc3QgdGhlIGVmZmVjdCBvZiBQb3NpdGlvbiBvbiB0aGUgUGhpIGNvZWZmaWNpZW50cyB3aXRoIChpbmRlcGVuZGVudCBtZWFzdXJlcykgQW5vdmEKY29uc2lzdGVuY3lfYW5vdmEgPC0gYW92KHBoaV9jb2VmZmljaWVudH5mYWN0b3IoUG9zaXRpb24pLCBkYXRhID0gc3ViX2NvcnJlbGF0aW9uKQpzdW1tYXJ5KGNvbnNpc3RlbmN5X2Fub3ZhKQoKIyBSdW4gdGhlIEFOT1ZBCmNvbnNpc3RlbmN5X2Fub3ZhIDwtIGFvdihwaGlfY29lZmZpY2llbnQgfiBmYWN0b3IoUG9zaXRpb24pLCBkYXRhID0gc3ViX2NvcnJlbGF0aW9uKQpzdW1tYXJ5KGNvbnNpc3RlbmN5X2Fub3ZhKQoKIyBQZXJmb3JtIFR1a2V5IEhTRCBwb3N0IGhvYyB0ZXN0CnR1a2V5X3Jlc3VsdCA8LSBUdWtleUhTRChjb25zaXN0ZW5jeV9hbm92YSkKCiMgRGlzcGxheSB0aGUgVHVrZXkgSFNEIHJlc3VsdApwcmludCh0dWtleV9yZXN1bHQpCgojIENhbGN1bGF0ZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgcGhpX2NvZWZmaWNpZW50IHBlciBQb3NpdGlvbgpzdW1tYXJ5X3N0YXRzIDwtIHN1Yl9jb3JyZWxhdGlvbiAlPiUKICBncm91cF9ieShQb3NpdGlvbikgJT4lCiAgc3VtbWFyaXNlKAogICAgbWVhbl9waGkgPSBtZWFuKHBoaV9jb2VmZmljaWVudCwgbmEucm0gPSBUUlVFKSwKICAgIHNkX3BoaSA9IHNkKHBoaV9jb2VmZmljaWVudCwgbmEucm0gPSBUUlVFKQogICkKCiMgUHJpbnQgdGhlIHN1bW1hcnkgc3RhdGlzdGljcwpwcmludChzdW1tYXJ5X3N0YXRzKQpgYGAKClBsb3Qgb2YgdGhlIHR3byBmaWd1cmVzIGZvciBFeHBlcmltZW50IDMKYGBge3J9CgpGaWd1cmVfMUMgPC0gZ3JpZC5hcnJhbmdlKFJlc3BvbnNlUGxvdCxDb25zaXN0ZW5jeVBsb3QsbmNvbCA9IDEpCgpgYGAKCgpFWFBFUklNRU5UIDQgKEF1dGhvcjogVGFsaXAgQXRhIEF5ZGluKQoKTG9hZGluZyB0aGUgbGlicmFyaWVzCgpgYGB7cn0KCiMgTG9hZCBldmVyeXRoaW5nIGVsc2UgZmlyc3QKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkocmVhZHIpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkodGlkeXIpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dwbG90MikpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh0aWR5dmVyc2UpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkocHN5Y2gpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkocmVhZHhsKSkpICAKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkocGF0Y2h3b3JrKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGNhVG9vbHMpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoY2FyKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHF1YW50bW9kKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KE1BU1MpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoY29ycnBsb3QpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZWZmZWN0cykpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh3cml0ZXhsKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHRpZHl0YWJsZSkpKSAgIApzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShzdHJpbmdyKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGFwZSkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShncmlkKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGdyaWRFeHRyYSkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShkcGx5cikpKQoKCmBgYAoKTG9hZGluZyB0aGUgZGF0YQpgYGB7cn0KYWxsX2RhdGEgPC0gcmVhZF9leGNlbCgiYWxsX2RhdGEueGxzeCIsCiAgICAgICAgICBzaGVldCA9ICJTaGVldDEiKQphbGxfdGFza3MgPC0gcmVhZF9leGNlbCgiYWxsX3Rhc2tzLnhsc3giLAogICAgICAgICAgIHNoZWV0ID0gIlNoZWV0MSIpCgpQQUdHIDwtIHJlYWRfZXhjZWwoIlBBR0cueGxzeCIsCiAgICBzaGVldCA9ICJTaGVldDEiKQoKZGVtb19kYXRhIDwtIHJlYWRfZXhjZWwoImRlbW9fZGF0YS54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAiU2hlZXQxIikKCmBgYAoKCiMjIyMjIyMjIyMjIyMKIE1BSU4gVEFTSyAKIyMjIyMjIyMjIyMjIwoKV2Ugd2lsbCBjcmVhdGUgYSBkYXRhZnJhbWUgZm9yIHRoZSBtYWluIHRhc2ssIHNpbmNlIHRoZSBvcmRlciBvZiB0aGUgc2xpZGVycyB3ZXJlIHJhbmRvbWl6ZWQgYWNyb3NzIDYgY29uZGl0aW9ucywgdGhlcmUgYXJlIDYgZGlmZmVyZW50IHRhc2sgbmFtZXMuIAoKbW9ucmEgPSBtdXNpYyBvciBub3QgcmF0aW5ncyAoV2hhdCBkbyB5b3UgdGhpbmsgdGhpcyBpcz8gMCA9IG5vdC1tdXNpYywgMTAwID0gbXVzaWMsIGFsbCBmZWF0dXJlcyBhcmUgYWxzbyByYXRlZCBvbiBzbGlkZXJzIGZyb20gMCB0byAxMDAuKQoKYGBge3J9CnJhdGluZ3MgPC0gYWxsX2RhdGEgJT4lCiAgZHBseXI6OnNlbGVjdCghbW9ucmEpICU+JQogIGZpbHRlcih0YXNrX25hbWUgJWluJSBjKCJDYXRlZ29yaXphdGlvbiIsICJDYXRlZ29yaXphdGlvbjIiLCAiQ2F0ZWdvcml6YXRpb24zIiwgIkNhdGVnb3JpemF0aW9uNCIsICJDYXRlZ29yaXphdGlvbjUiLCAiQ2F0ZWdvcml6YXRpb242IikpICU+JQogIGxlZnRfam9pbigKICAgIGFsbF9kYXRhICU+JQogICAgICBmaWx0ZXIodGFza19uYW1lICVpbiUgYygiTXVzaWNfb3Jfbm90IikpICU+JQogICAgICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCBhdWRpb19uYW1lLCBtb25yYSksCiAgICBqb2luX2J5KGV4cF9zdWJqZWN0X2lkLCBhdWRpb19uYW1lKQogICkgJT4lCiAgZmlsdGVyKCFhdWRpb19ncm91cCA9PSAic2lnbmFsIikgJT4lCiAgZHBseXI6OnNlbGVjdChleHBfc3ViamVjdF9pZCwgYXVkaW9fbmFtZSwgbW9ucmEsIHB1bHNlLCByaHl0aG0sIHJlcGV0aXRpb24sIG1lbG9keSwgaW5zdHJ1bWVudGFsLCB0aW1icmUsIHRlbXBvLCBpbnRlbnRpb25hbGl0eSwgaGFybW9ueSwgY29tcGxleGl0eSwgcGFnKQoKCiNOb3cgdGhlIGxvbmcgZm9ybWF0IG9mIHRoZSBzYW1lIGRhdGFmcmFtZQoKcmF0aW5nc19sb25nIDwtIHBpdm90X2xvbmdlcihyYXRpbmdzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKG1vbnJhLCBwdWxzZSwgcmh5dGhtLCByZXBldGl0aW9uLCBtZWxvZHksIGluc3RydW1lbnRhbCwgdGltYnJlLCB0ZW1wbywgaW50ZW50aW9uYWxpdHksIGhhcm1vbnksIGNvbXBsZXhpdHkpLCAjIHNlbGVjdCBjb2x1bW5zIHRvIHBpdm90CiAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsICAgICAjIG5ldyBjb2x1bW4gbmFtZSBmb3IgdmFyaWFibGUgbmFtZXMKICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogICBtdXRhdGUobGV2ZWxzID0gY2FzZV93aGVuKAogICAgdmFyaWFibGUgJWluJSBjKCJpbnN0cnVtZW50YWwiLCAiaW50ZW50aW9uYWxpdHkiLCAiY29tcGxleGl0eSIsICJyZXBldGl0aW9uIikgfiAzLAogICAgdmFyaWFibGUgJWluJSBjKCJoYXJtb255IiwgIm1lbG9keSIsICJyaHl0aG0iKSB+IDIsCiAgICB2YXJpYWJsZSAlaW4lIGMoInRpbWJyZSIsICJwdWxzZSIsICJ0ZW1wbyIpIH4gMSwKICAgIFRSVUUgfiBOQV9pbnRlZ2VyXyAgIyBEZWZhdWx0IGNhc2UgaWYgbm9uZSBvZiB0aGUgY29uZGl0aW9ucyBtYXRjaAogICkpCgpyYXRpbmdzX2xvbmdfd29fbW9ucmEgPC0gcmF0aW5nc19sb25nICU+JQogIGZpbHRlcighdmFyaWFibGUgPT0gIm1vbnJhIikKcmF0aW5nc19sb25nX211c2ljIDwtIHJhdGluZ3NfbG9uZyAlPiUKICBmaWx0ZXIodmFyaWFibGUgPT0gIm1vbnJhIikKCnJhdGluZ3NfbG9uZzIgPC0gcGl2b3RfbG9uZ2VyKHJhdGluZ3MsIAogICAgICAgICAgICAgICAgICAgICAgICAgY29scyA9IGMocHVsc2UsIHJoeXRobSwgcmVwZXRpdGlvbiwgbWVsb2R5LCBpbnN0cnVtZW50YWwsIHRpbWJyZSwgdGVtcG8sIGludGVudGlvbmFsaXR5LCBoYXJtb255LCBjb21wbGV4aXR5KSwgIyBzZWxlY3QgY29sdW1ucyB0byBwaXZvdAogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidmFyaWFibGUiLCAgICAgIyBuZXcgY29sdW1uIG5hbWUgZm9yIHZhcmlhYmxlIG5hbWVzCiAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICAgbXV0YXRlKGxldmVscyA9IGNhc2Vfd2hlbigKICAgIHZhcmlhYmxlICVpbiUgYygiaW5zdHJ1bWVudGFsIiwgImludGVudGlvbmFsaXR5IiwgImNvbXBsZXhpdHkiLCAicmVwZXRpdGlvbiIpIH4gMywKICAgIHZhcmlhYmxlICVpbiUgYygiaGFybW9ueSIsICJtZWxvZHkiLCAicmh5dGhtIikgfiAyLAogICAgdmFyaWFibGUgJWluJSBjKCJ0aW1icmUiLCAicHVsc2UiLCAidGVtcG8iKSB+IDEsCiAgICBUUlVFIH4gTkFfaW50ZWdlcl8gICMgRGVmYXVsdCBjYXNlIGlmIG5vbmUgb2YgdGhlIGNvbmRpdGlvbnMgbWF0Y2gKICApKQpgYGAKCgpDcmVhdGluZyB0aGUgZGF0YWZyYW1lcyBmb3IgbXVzaWNhbCBzb3BoaXN0aWNhdGlvbiBpbmRleCAoR29sZC1NU0kpIGFuZCBhdWRpdG9yeSBpbWFnZXJ5ICh2aXZpZG5lc3MsIEJBSVMtVikKCmBgYHtyfQpyYXRpbmdzX3NjYWxlcyA8LSBkcGx5cjo6c2VsZWN0KGFsbF9kYXRhLCBleHBfc3ViamVjdF9pZCwgdGFza19uYW1lLCBhdWRpb19uYW1lLCBhdWRpb19ncm91cCwgbW9ucmEsIHB1bHNlLCByZXBldGl0aW9uLCByaHl0aG0sIG1lbG9keSwgaW5zdHJ1bWVudGFsLCB0aW1icmUsIHRlbXBvLCBpbnRlbnRpb25hbGl0eSwgaGFybW9ueSwgY29tcGxleGl0eSwgYWVfMDEsIGFlXzAyLCBhZV8wNSwgYWVfMDcsIGJhaXN2XzAxLCBiYWlzdl8wMiwgYmFpc3ZfMDMsIGJhaXN2XzA0LCBiYWlzdl8wNSwgYmFpc3ZfMDYsIGJhaXN2XzA3LCBiYWlzdl8wOCwgYmFpc3ZfMDksIGJhaXN2XzEwLCBiYWlzdl8xMSwgYmFpc3ZfMTIsIGJhaXN2XzEzLCBiYWlzdl8xNCwgbXRfMDEsIG10XzAyLCBtdF8wMywgbXRfMDYsIG10XzA3LCBwYV8wNCwgcGFfMDgsIHNhXzAxLCBzYV8wMiwgc2FfMDMsIHNhXzA0LCBzYV8wNSwgc2FfMDYsIGVtXzA0KQoKcmF0aW5ncyA8LSBhbGxfZGF0YSAlPiUKICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCB0YXNrX25hbWUsIGF1ZGlvX25hbWUsIGF1ZGlvX2dyb3VwLCBtb25yYSwgcHVsc2UsIHJlcGV0aXRpb24sIHJoeXRobSwgbWVsb2R5LCBpbnN0cnVtZW50YWwsIHRpbWJyZSwgdGVtcG8sIGludGVudGlvbmFsaXR5LCBoYXJtb255LCBjb21wbGV4aXR5KSAlPiUKICBuYS5vbWl0KCkKCgpyYXRpbmdzIDwtIGFsbF9kYXRhICU+JQogIGZpbHRlcih0YXNrX25hbWUgJWluJSBjKCJDYXRlZ29yaXphdGlvbiIsICJDYXRlZ29yaXphdGlvbjIiLCAiQ2F0ZWdvcml6YXRpb24zIiwgIkNhdGVnb3JpemF0aW9uNCIsICJDYXRlZ29yaXphdGlvbjUiLCAiQ2F0ZWdvcml6YXRpb242IikpICU+JQogIGRwbHlyOjpzZWxlY3QoZXhwX3N1YmplY3RfaWQsIGF1ZGlvX25hbWUsIHB1bHNlLCByZXBldGl0aW9uLCByaHl0aG0sIG1lbG9keSwgaW5zdHJ1bWVudGFsLCB0aW1icmUsIHRlbXBvLCBpbnRlbnRpb25hbGl0eSwgaGFybW9ueSwgY29tcGxleGl0eSkgJT4lCiAgbGVmdF9qb2luKAogICAgYWxsX2RhdGEgJT4lCiAgICAgIGZpbHRlcighYXVkaW9fZ3JvdXAgPT0gInNpZ25hbCIpICU+JQogICAgICBmaWx0ZXIodGFza19uYW1lICVpbiUgYygiTXVzaWNfb3Jfbm90IikpICU+JQogICAgICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCBhdWRpb19uYW1lLCBtb25yYSksCiAgICBqb2luX2J5KGV4cF9zdWJqZWN0X2lkLCBhdWRpb19uYW1lKQogICkKCnJhdGluZ3MgPC0gbWVyZ2UocmF0aW5ncywgUEFHRywgYnkgPSAiYXVkaW9fbmFtZSIpCgpgYGAKCgoKRmlsdGVyIG9ubHkgdGhlIGNhdGVnb3JpemF0aW9uIHRhc2sgYW5kIHRoZW4gZmlsdGVyIG91dCB0aGUgc2lnbmFsIHNvdW5kcwpgYGB7cn0KI09ubHkgcmF0aW5ncyBvZiBwZXJjZXB0dWFsIGZlYXR1cmVzCgpmZWF0dXJlc19kYXRhIDwtIHJhdGluZ3Nfc2NhbGVzICU+JQogIGZpbHRlcih0YXNrX25hbWUgJWluJSBjKCJDYXRlZ29yaXphdGlvbiIsICJDYXRlZ29yaXphdGlvbjIiLCAiQ2F0ZWdvcml6YXRpb24zIiwgIkNhdGVnb3JpemF0aW9uNCIsICJDYXRlZ29yaXphdGlvbjUiLCAiQ2F0ZWdvcml6YXRpb242IiksCiAgICAgICAgICFhdWRpb19ncm91cCA9PSAic2lnbmFsIikgJT4lCiAgZHBseXI6OnNlbGVjdChleHBfc3ViamVjdF9pZCwgYXVkaW9fbmFtZSwgcHVsc2UsIHJoeXRobSwgcmVwZXRpdGlvbiwgbWVsb2R5LCBpbnN0cnVtZW50YWwsIHRpbWJyZSwgdGVtcG8sIGludGVudGlvbmFsaXR5LCBoYXJtb255LCBjb21wbGV4aXR5KQoKI09ubHkgbXVzaWMgb3Igbm90IHJhdGluZ3MKbW9ucmFfZGF0YSA8LSByYXRpbmdzX3NjYWxlcyAlPiUKICBmaWx0ZXIodGFza19uYW1lICVpbiUgYygiTXVzaWNfb3Jfbm90IiksCiAgICAgICAgICFhdWRpb19ncm91cCA9PSAic2lnbmFsIikgJT4lCiAgZHBseXI6OnNlbGVjdChleHBfc3ViamVjdF9pZCwgYXVkaW9fbmFtZSwgbW9ucmEpCgp3cml0ZV94bHN4KG1vbnJhX2RhdGEsICJtb25yYV9kYXRhLnhsc3giKQoKYGBgCgoKCkRhdGEgRnJhbWVzIGZvciBNTTEgYW5hbHlzaXMKCmBgYHtyfQoKbW9ucmFfbW0xIDwtIG1vbnJhX2RhdGEgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGF1ZGlvX25hbWUsIHZhbHVlc19mcm9tID0gbW9ucmEpCgpwdWxzZV9tbTEgPC0gZmVhdHVyZXNfZGF0YSAlPiUKICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCBhdWRpb19uYW1lLCBwdWxzZSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGF1ZGlvX25hbWUsIHZhbHVlc19mcm9tID0gcHVsc2UpCgpyZXBldGl0aW9uX21tMSA8LSBmZWF0dXJlc19kYXRhICU+JQogIGRwbHlyOjpzZWxlY3QoZXhwX3N1YmplY3RfaWQsIGF1ZGlvX25hbWUsIHJlcGV0aXRpb24pICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBhdWRpb19uYW1lLCB2YWx1ZXNfZnJvbSA9IHJlcGV0aXRpb24pCgpyaHl0aG1fbW0xIDwtIGZlYXR1cmVzX2RhdGEgJT4lCiAgZHBseXI6OnNlbGVjdChleHBfc3ViamVjdF9pZCwgYXVkaW9fbmFtZSwgcmh5dGhtKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYXVkaW9fbmFtZSwgdmFsdWVzX2Zyb20gPSByaHl0aG0pCgptZWxvZHlfbW0xIDwtIGZlYXR1cmVzX2RhdGEgJT4lCiAgZHBseXI6OnNlbGVjdChleHBfc3ViamVjdF9pZCwgYXVkaW9fbmFtZSwgbWVsb2R5KSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYXVkaW9fbmFtZSwgdmFsdWVzX2Zyb20gPSBtZWxvZHkpCgppbnN0cnVtZW50YWxfbW0xIDwtIGZlYXR1cmVzX2RhdGEgJT4lCiAgZHBseXI6OnNlbGVjdChleHBfc3ViamVjdF9pZCwgYXVkaW9fbmFtZSwgaW5zdHJ1bWVudGFsKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYXVkaW9fbmFtZSwgdmFsdWVzX2Zyb20gPSBpbnN0cnVtZW50YWwpCgp0aW1icmVfbW0xIDwtIGZlYXR1cmVzX2RhdGEgJT4lCiAgZHBseXI6OnNlbGVjdChleHBfc3ViamVjdF9pZCwgYXVkaW9fbmFtZSwgdGltYnJlKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYXVkaW9fbmFtZSwgdmFsdWVzX2Zyb20gPSB0aW1icmUpCgp0ZW1wb19tbTEgPC0gZmVhdHVyZXNfZGF0YSAlPiUKICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCBhdWRpb19uYW1lLCB0ZW1wbykgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGF1ZGlvX25hbWUsIHZhbHVlc19mcm9tID0gdGVtcG8pCgppbnRlbnRpb25hbGl0eV9tbTEgPC0gZmVhdHVyZXNfZGF0YSAlPiUKICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCBhdWRpb19uYW1lLCBpbnRlbnRpb25hbGl0eSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGF1ZGlvX25hbWUsIHZhbHVlc19mcm9tID0gaW50ZW50aW9uYWxpdHkpCgpoYXJtb255X21tMSA8LSBmZWF0dXJlc19kYXRhICU+JQogIGRwbHlyOjpzZWxlY3QoZXhwX3N1YmplY3RfaWQsIGF1ZGlvX25hbWUsIGhhcm1vbnkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBhdWRpb19uYW1lLCB2YWx1ZXNfZnJvbSA9IGhhcm1vbnkpCgpjb21wbGV4aXR5X21tMSA8LSBmZWF0dXJlc19kYXRhICU+JQogIGRwbHlyOjpzZWxlY3QoZXhwX3N1YmplY3RfaWQsIGF1ZGlvX25hbWUsIGNvbXBsZXhpdHkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBhdWRpb19uYW1lLCB2YWx1ZXNfZnJvbSA9IGNvbXBsZXhpdHkpCgoKYGBgCgoKQSBtb3JlIGRlc2NyaXB0aXZlIERGIHRoYXQgd2Ugd2lsbCB1c2UsIHRoZSBtZWFuIHJhdGluZ3Mgb2YgYWxsIHNsaWRlcnMgKG1vbnJhICsgZmVhdHVyZXMpIGF0IHRoZSBTVElNVUxVUyBsZXZlbCEKCmBgYHtyfQphdWRpb19kZXNjcmlwdGl2ZXMgPC0gcmF0aW5ncyAlPiUKICBncm91cF9ieShhdWRpb19uYW1lKSAlPiUKICBzdW1tYXJpemUoCiAgICAgICAgICAgIG1lYW5fbW9ucmEgPSBtZWFuKG1vbnJhLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX3B1bHNlID0gbWVhbihwdWxzZSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWVhbl9yZXBldGl0aW9uID0gbWVhbihyZXBldGl0aW9uLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX3JoeXRobSA9IG1lYW4ocmh5dGhtLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX21lbG9keSA9IG1lYW4obWVsb2R5LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX2luc3RydW1lbnRhbCA9IG1lYW4oaW5zdHJ1bWVudGFsLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX3RpbWJyZSA9IG1lYW4odGltYnJlLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWFuX3RlbXBvID0gbWVhbih0ZW1wbywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWVhbl9pbnRlbnRpb25hbGl0eSA9IG1lYW4oaW50ZW50aW9uYWxpdHksIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG1lYW5faGFybW9ueSA9IG1lYW4oaGFybW9ueSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWVhbl9jb21wbGV4aXR5ID0gbWVhbihjb21wbGV4aXR5LCBuYS5ybSA9IFRSVUUpKQoKYXVkaW9fZGVzY3JpcHRpdmVzIDwtIG1lcmdlKGF1ZGlvX2Rlc2NyaXB0aXZlcywgUEFHRywgYnkgPSAiYXVkaW9fbmFtZSIpCgoKYXVkaW9fZGVzY3JpcHRpdmVzX2xvbmcgPC0gcGl2b3RfbG9uZ2VyKGF1ZGlvX2Rlc2NyaXB0aXZlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKG1lYW5fbW9ucmEsIG1lYW5fcHVsc2UsIG1lYW5fcmh5dGhtLCBtZWFuX3JlcGV0aXRpb24sIG1lYW5fbWVsb2R5LCBtZWFuX2luc3RydW1lbnRhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuX3RpbWJyZSwgbWVhbl90ZW1wbywgbWVhbl9pbnRlbnRpb25hbGl0eSwgbWVhbl9oYXJtb255LCBtZWFuX2NvbXBsZXhpdHkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsdWUiKQpgYGAKCgpXZSBkbyB0aGUgay1tZWFucyBjbHVzdGVyaW5nIGhlcmUuIFRoaXMgaXMgYmVjYXVzZSB0aGUgY2x1c3RlcnMgd2lsbCB0aGVuIGJlIHVzZWQgZm9yIGZ1cnRoZXIgYW5hbHlzaXMgZXRjLiBhbmQgd2UgdGhvdWdodCBpdCBtYWtlcyBtb3JlIHNlbnNlIHRvIHB1dCB0aGUgY2x1c3RlciBhbmFseXNpcyBoZXJlLiAKCkJlY2F1c2UgUiBnaXZlcyByYW5kb20gbnVtYmVycyB0byBjbHVzdGVycyBlYWNoIHRpbWUgd2UgcnVuIHRoZSBhbmFseXNlcywgd2Ugd2lsbCBzaW1wbHkgdXBsb2FkIHRoZSBmaWxlIHdpdGggY2x1c3RlcnMsIHRoZSBjb2RlIHRvIGZpbmQgdGhvc2UgY2x1c3RlcnMgYXJlIGNvbW1lbnRlZCBvdXQuIAoKV2UgZGVjaWRlZCB0aGF0IGEgMy1jbHVzdGVyLXNvbHV0aW9uIGlzIHRoZSBiZXN0LiBMb29raW5nIGF0IHRoZW0sIHRoZXJlIGlzIG9uZSB3aXRoIG11c2ljIHN0aW11bGkgKG11c2ljIGNsdXN0ZXIpLCBhbm90aGVyIHdpdGggbm90LW11c2ljIHN0aW11bGkgKG5vdC1tdXNpYyBjbHVzdGVyLCBhbHRob3VnaCBpbiB0aGUgY29kZSB5b3UgbWlnaHQgc2VlIGl0IGFzICJub24tbXVzaWMiKSwgYW5kIHRoZW4gYSBjbHVzdGVyIGluIGJldHdlZW4sIHdoaWNoIHdlIGNhbGwgdGhlICJhbWJpZ3VvdXMgY2x1c3RlciIuIAoKYGBge3J9CiMgIyBBc3N1bWluZyB5b3UgaGF2ZSBsb2FkZWQgeW91ciBkYXRhIGZyYW1lICdhdWRpb19kZXNjcmlwdGl2ZXMnIGNvcnJlY3RseQojIGp1c3RtZWFucyA8LSBkcGx5cjo6c2VsZWN0KGF1ZGlvX2Rlc2NyaXB0aXZlcywgYXVkaW9fbmFtZSwgbWVhbl9tb25yYSkKIyAKIyAjIFBlcmZvcm0gay1tZWFucyBjbHVzdGVyaW5nCiMga21tIDwtIGttZWFucyhqdXN0bWVhbnMkbWVhbl9tb25yYSwgMywgbnN0YXJ0ID0gNTAsIGl0ZXIubWF4ID0gMTUpCiMgcHJpbnQoa21tKQojIHByaW50KGttbSRiZXR3ZWVuc3MgLyBrbW0kdG90c3MpCiMgCiMgIyBNZXRob2QgMTogRWxib3cgTWV0aG9kIGZvciBmaW5kaW5nIHRoZSBvcHRpbWFsIG51bWJlciBvZiBjbHVzdGVycwojIHNldC5zZWVkKDEyMykKIyAKIyAjIENvbXB1dGUgYW5kIHBsb3Qgd3NzIGZvciBrID0gMiB0byBrID0gMTUKIyBrLm1heCA8LSAxNQojIGRhdGEgPC0ganVzdG1lYW5zJG1lYW5fbW9ucmEgICMgRW5zdXJlIHRoaXMgaXMgdGhlIGNvcnJlY3QgY29sdW1uIG5hbWUKIyBkYXRhIDwtIG5hLm9taXQoZGF0YSkgICMgUmVtb3ZlIE5BIHZhbHVlcyBpZiBhbnkKIyAKIyB3c3MgPC0gc2FwcGx5KDE6ay5tYXgsIGZ1bmN0aW9uKGspIHsKIyAgIGttZWFucyhkYXRhLCBrLCBuc3RhcnQgPSA1MCwgaXRlci5tYXggPSAxNSkkdG90LndpdGhpbnNzCiMgfSkKIyAKIyAjIFBsb3QgdGhlIHJlc3VsdHMKIyBwbG90KDE6ay5tYXgsIHdzcywKIyAgICAgIHR5cGUgPSAiYiIsIHBjaCA9IDE5LCBmcmFtZSA9IEZBTFNFLCAKIyAgICAgIHhsYWIgPSAiTnVtYmVyIG9mIGNsdXN0ZXJzIiwKIyAgICAgIHlsYWIgPSAiVG90YWwgV2l0aGluLUNsdXN0ZXJzIFN1bSBvZiBTcXVhcmVzIikKIyAKIyAKIyAKIyBqdXN0bWVhbnMgPC0ganVzdG1lYW5zICU+JSAKIyAgIG11dGF0ZShjbHVzdGVyID0ga21tJGNsdXN0ZXIpCiMgCiMgIyBWaWV3IHRoZSBmaXJzdCBmZXcgcm93cyBvZiB0aGUgdXBkYXRlZCBkYXRhIGZyYW1lCiMgaGVhZChqdXN0bWVhbnMpCgojd3JpdGVfeGxzeChqdXN0bWVhbnMsICJqdXN0bWVhbnMueGxzeCIpCgoKI0xvYWRpbmcgdGhlIGRhdGEgd2l0aCBzdGltdWxpLCBjbHVzdGVyIGxhYmVscywgYW5kIGNsdXN0ZXIgbnVtYmVycyAobnVtYmVycyB3aWxsIGJlIGlycmVsZXZhbnQpCgpqdXN0bWVhbnMgPC0gcmVhZF9leGNlbCgianVzdG1lYW5zLnhsc3giLAogICAgICAgICAgIHNoZWV0ID0gIlNoZWV0MSIpCgoKCmBgYAoKCmBgYHtyfQoKIyBDcmVhdGUgYSBzZXBhcmF0ZSBkYXRhIGZyYW1lIGNhbGxlZCBhdWRpb19jbHVzdGVycyBmb3IgY2xhcml0eSBhbmQgZnV0dXJlIHVzZQphdWRpb19jbHVzdGVycyA8LSBqdXN0bWVhbnMgJT4lIAogIGRwbHlyOjpzZWxlY3QoYXVkaW9fbmFtZSwgY2x1c3RlcikgJT4lCiAgbXV0YXRlKGxhYmVsID0gY2FzZV93aGVuKAogICAgY2x1c3RlciA9PSAxIH4gIm11c2ljIiwKICAgIGNsdXN0ZXIgPT0gMiB+ICJhbWJpZ3VvdXMiLAogICAgY2x1c3RlciA9PSAzIH4gIm5vbi1tdXNpYyIpKQoKYXVkaW9fY2x1c3RlcnMgPC0gYXVkaW9fY2x1c3RlcnMgJT4lCiAgbXV0YXRlKGNsZWFuX25hbWVzID0gYXVkaW9fbmFtZSAlPiUKICAgICAgICAgICBnc3ViKCJeKE1ffE5fKSIsICIiLCAuKSAlPiUgICMgUmVtb3ZlIE1fIG9yIE5fIGF0IHRoZSBzdGFydAogICAgICAgICAgIGdzdWIoIlxcLm1wMyQiLCAiIiwgLikgJT4lICAjIFJlbW92ZSAubXAzIGF0IHRoZSBlbmQKICAgICAgICAgICBnc3ViKCJfIiwgIiAiLCAuKSAlPiUgICAgICAgIyBSZXBsYWNlIHVuZGVyc2NvcmVzIHdpdGggc3BhY2VzCiAgICAgICAgICAgc3RyX3RvX3RpdGxlKCkgICAgICAgICAgICAgICMgQ2FwaXRhbGl6ZSBlYWNoIHdvcmQKICAgICAgICAgKQoKYXVkaW9fZGVzY3JpcHRpdmVzIDwtIG1lcmdlKGF1ZGlvX2Rlc2NyaXB0aXZlcywgYXVkaW9fY2x1c3RlcnMsIGJ5ID0gImF1ZGlvX25hbWUiKQoKI0luY2x1ZGluZyB0aGUgY2x1c3RlciBjb2x1bW4gdG8gb3RoZXIgZGF0YWZyYW1lcwoKcmF0aW5ncyA8LSByYXRpbmdzICU+JQogIGxlZnRfam9pbihhdWRpb19jbHVzdGVycyAlPiUKICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGF1ZGlvX25hbWUsIGxhYmVsLCBjbHVzdGVyKSwKICAgICAgICAgICAgYnkgPSAiYXVkaW9fbmFtZSIpCgpyYXRpbmdzX2xvbmcgPC0gcmF0aW5nc19sb25nICU+JQogIGxlZnRfam9pbihhdWRpb19jbHVzdGVycyAlPiUKICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGF1ZGlvX25hbWUsIGxhYmVsKSwKICAgICAgICAgICAgYnkgPSAiYXVkaW9fbmFtZSIpCgpyYXRpbmdzX2xvbmdfd29fbW9ucmEgPC0gcmF0aW5nc19sb25nX3dvX21vbnJhICU+JQogIGxlZnRfam9pbihhdWRpb19jbHVzdGVycyAlPiUKICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGF1ZGlvX25hbWUsIGxhYmVsKSwKICAgICAgICAgICAgYnkgPSAiYXVkaW9fbmFtZSIpCgpyYXRpbmdzX2xtZSA8LSByYXRpbmdzCgp3cml0ZV94bHN4KGF1ZGlvX2Rlc2NyaXB0aXZlcywgImF1ZGlvX2Rlc2NyaXB0aXZlcy54bHN4IikKCndyaXRlX3hsc3gocmF0aW5ncywgInJhdGluZ3MueGxzeCIpCgpgYGAKCgpBIGRhdGFmcmFtZSBmb3IgdGhlIG1lYW5zIG9mIGFsbCBhdWRpb3MKYGBge3J9CgphdWRpb19mZWF0dXJlcyA8LSBkcGx5cjo6c2VsZWN0KGF1ZGlvX2Rlc2NyaXB0aXZlcywgYXVkaW9fbmFtZSwgbWVhbl9tb25yYSwgbWVhbl9wdWxzZSwgbWVhbl9yaHl0aG0sIG1lYW5fcmVwZXRpdGlvbiwgbWVhbl9tZWxvZHksIG1lYW5faW5zdHJ1bWVudGFsLCBtZWFuX3RpbWJyZSwgbWVhbl90ZW1wbywgbWVhbl9pbnRlbnRpb25hbGl0eSwgbWVhbl9oYXJtb255LCBtZWFuX2NvbXBsZXhpdHksIGxhYmVsKQoKd3JpdGVfeGxzeChhdWRpb19mZWF0dXJlcywgImF1ZGlvX2ZlYXR1cmVzLnhsc3giKQoKYGBgCgoKClBhcnRpY2lwYW50IG1lYW5zLCBhdmVyYWdlIHZhbHVlcyBhdCB0aGUgcGFydGljaXBhbnQgbGV2ZWwKYGBge3J9CgpwYXJ0aWNpcGFudF9tZWFucyA8LSByYXRpbmdzICU+JQogIGdyb3VwX2J5KGV4cF9zdWJqZWN0X2lkKSAlPiUKICBzdW1tYXJpemUoYWNyb3NzKC5jb2xzID0gYyhtb25yYSwgcHVsc2UsIHJoeXRobSwgcmVwZXRpdGlvbiwgbWVsb2R5LCBpbnN0cnVtZW50YWwsIHRpbWJyZSwgdGVtcG8sIGludGVudGlvbmFsaXR5LCBoYXJtb255LCBjb21wbGV4aXR5KSwgLmZucyA9IG1lYW4pKQoKCmBgYAoKCgpDYWxjdWxhdGUgR29sZC1NU0kKYGBge3J9Cgpnb2xkIDwtIGRwbHlyOjpzZWxlY3QoYWxsX3Rhc2tzLCBleHBfc3ViamVjdF9pZCwgYWVfMDEsIGFlXzAyLCBhZV8wNSwgYWVfMDcsIG10XzAxLCBtdF8wMiwgbXRfMDMsIG10XzA2LCBtdF8wNywgcGFfMDQsIHBhXzA4LCBzYV8wMSwgc2FfMDIsIHNhXzAzLCBzYV8wNCwgc2FfMDUsIHNhXzA2LCBlbV8wNCkKCmdvbGQgPC0gYWdncmVnYXRlZF9kYXRhIDwtIGFnZ3JlZ2F0ZSguIH4gZXhwX3N1YmplY3RfaWQsIGRhdGEgPSBnb2xkLCBGVU4gPSBmdW5jdGlvbih4KSB4WyFpcy5uYSh4KV1bMV0pCgpnb2xkMjwtZHBseXI6OnNlbGVjdChnb2xkLCAhIGV4cF9zdWJqZWN0X2lkKQoKa2V5c19nb2xkIDwtIGMoInNhXzA1IiwgInNhXzA0IiwgIm10XzAzIiwgIm10XzA3IiwgInBhXzA4IikKCnJlYyA8LSAgcHN5Y2g6OnJldmVyc2UuY29kZShrZXlzID0ga2V5c19nb2xkLCBpdGVtcyA9IGdvbGQyLCBtaW5pID0gMSwgbWF4aSA9IDcpIAoKIyBWaWV3KHJlYykKcmVjIDwtIGFzLmRhdGEuZnJhbWUocmVjKQoKI0dNX3N1bSAKcmVjJGdvbGQ9cm93U3VtcyhjYmluZChyZWMkYWVfMDEscmVjJGFlXzAyLHJlYyRhZV8wNSxyZWMkYWVfMDcscmVjJGVtXzA0LHJlYyRtdF8wMSxyZWMkbXRfMDIscmVjJGBtdF8wMy1gLHJlYyRtdF8wNixyZWMkYG10XzA3LWAscmVjJHBhXzA0LHJlYyRgcGFfMDgtYCxyZWMkc2FfMDEscmVjJHNhXzAyLHJlYyRzYV8wMyxyZWMkYHNhXzA0LWAscmVjJGBzYV8wNS1gLHJlYyRzYV8wNikpCgpyZWMkZXhwX3N1YmplY3RfaWQgPC0gZ29sZCRleHBfc3ViamVjdF9pZApnb2xkX3Njb3JlIDwtIGRwbHlyOjpzZWxlY3QocmVjLCBleHBfc3ViamVjdF9pZCwgZ29sZCkKCgpgYGAKCgpDYWxjdWxhdGUgQkFJUy1WCmBgYHtyfQoKYmFpcyA8LSBkcGx5cjo6c2VsZWN0KGFsbF90YXNrcywgZXhwX3N1YmplY3RfaWQsIGJhaXN2XzAxLCBiYWlzdl8wMiwgYmFpc3ZfMDMsIGJhaXN2XzA0LCBiYWlzdl8wNSwgYmFpc3ZfMDYsIGJhaXN2XzA3LCBiYWlzdl8wOCwgYmFpc3ZfMDksIGJhaXN2XzEwLCBiYWlzdl8xMCwgYmFpc3ZfMTEsIGJhaXN2XzEyLCBiYWlzdl8xMywgYmFpc3ZfMTQpCmJhaXMgPC0gbmEub21pdChiYWlzKQpyZWMgPC0gYXMuZGF0YS5mcmFtZShiYWlzKQoKI01lYW5fc2NvcmUKcmVjJGJhaXM9cm93TWVhbnMoY2JpbmQocmVjJGJhaXN2XzAxLHJlYyRiYWlzdl8wMixyZWMkYmFpc3ZfMDMscmVjJGJhaXN2XzA0LHJlYyRiYWlzdl8wNSxyZWMkYmFpc3ZfMDYscmVjJGJhaXN2XzA3LHJlYyRiYWlzdl8wOCxyZWMkYmFpc3ZfMDkscmVjJGJhaXN2XzEwLHJlYyRiYWlzdl8xMSxyZWMkYmFpc3ZfMTIscmVjJGJhaXN2XzEzLHJlYyRiYWlzdl8xNCkpCgpCQUlTX3Njb3JlPC1kcGx5cjo6c2VsZWN0KHJlYyxiYWlzKQpCQUlTX3Njb3JlIDwtIGNiaW5kKEJBSVNfc2NvcmUsIGJhaXMkZXhwX3N1YmplY3RfaWQpCmNvbG5hbWVzKEJBSVNfc2NvcmUpW2NvbG5hbWVzKEJBSVNfc2NvcmUpID09ICJCQUlTX3Njb3JlJGV4cF9zdWJqZWN0X2lkIl0gPC0gImV4cF9zdWJqZWN0X2lkIgoKc2NhbGVzIDwtY2JpbmQoZ29sZF9zY29yZSwgQkFJU19zY29yZSkKCmBgYAoKCkNhbGN1bGF0ZSBPcGVubmVzcwpgYGB7cn0KCm9wZW5uZXNzIDwtIGRwbHlyOjpzZWxlY3QoYWxsX3Rhc2tzLCBleHBfc3ViamVjdF9pZCwgb3BlbjEsIG9wZW4yLCBvcGVuMywgb3BlbjQsIG9wZW41LCBvcGVuNiwgb3BlbjcsIG9wZW44LCBvcGVuOSwgb3BlbjEwKQoKcmV2ZXJzZV9jb2RlIDwtIGZ1bmN0aW9uKHgpIHsKICByZXR1cm4oNiAtIHgpCn0KCiMgQXBwbHkgcmV2ZXJzZSBjb2RpbmcgYW5kIGNhbGN1bGF0ZSB0b3RhbF9vcGVubmVzcwpvcGVubmVzcyA8LSBvcGVubmVzcyAlPiUKICBtdXRhdGUoCiAgICBvcGVuMiA9IHJldmVyc2VfY29kZShvcGVuMiksCiAgICBvcGVuNCA9IHJldmVyc2VfY29kZShvcGVuNCksCiAgICBvcGVuNiA9IHJldmVyc2VfY29kZShvcGVuNiksCiAgICBvcGVuOCA9IHJldmVyc2VfY29kZShvcGVuOCksCiAgICBvcGVuMTAgPSByZXZlcnNlX2NvZGUob3BlbjEwKQogICkgJT4lCiAgZ3JvdXBfYnkoZXhwX3N1YmplY3RfaWQpICU+JQogIHN1bW1hcmlzZSh0b3RhbF9vcGVubmVzcyA9IHN1bShjX2Fjcm9zcyhvcGVuMTpvcGVuMTApLCBuYS5ybSA9IFRSVUUpKQoKIyBWaWV3IHRoZSByZXN1bHQKcHJpbnQob3Blbm5lc3MpCgojIE1lcmdlIGFsbCBzY2FsZXMgaW4gb25lIGRhdGFmcmFtZQphbGxfc2NhbGVzIDwtIG1lcmdlKHNjYWxlcywgb3Blbm5lc3MsIGJ5ID0iZXhwX3N1YmplY3RfaWQiKQphbGxfc2NhbGVzIDwtIGFsbF9zY2FsZXMgCgoKbWVhbihhbGxfc2NhbGVzJHRvdGFsX29wZW5uZXNzKQpzZChhbGxfc2NhbGVzJHRvdGFsX29wZW5uZXNzKQptaW4oYWxsX3NjYWxlcyR0b3RhbF9vcGVubmVzcykKbWF4KGFsbF9zY2FsZXMkdG90YWxfb3Blbm5lc3MpCgptZWFuKGFsbF9zY2FsZXMkYmFpcykKc2QoYWxsX3NjYWxlcyRiYWlzKQptaW4oYWxsX3NjYWxlcyRiYWlzKQptYXgoYWxsX3NjYWxlcyRiYWlzKQoKbWVhbihhbGxfc2NhbGVzJGdvbGQpCnNkKGFsbF9zY2FsZXMkZ29sZCkKbWluKGFsbF9zY2FsZXMkZ29sZCkKbWF4KGFsbF9zY2FsZXMkZ29sZCkKCmBgYAoKCkxldCdzIGNvbXB1dGUgaG93IHdlbGwgcGFydGljaXBhbnRzIHVuZGVyc3Rvb2QgdGhlIGRlZmluaXRpb25zIG9mIGZlYXR1cmVzIHRoYXQgd2UgcHJvdmlkZWQhCgpgYGB7cn0KCnVuZGVyc3RhbmRpbmcgPC0gYWxsX3Rhc2tzICU+JQogIGRwbHlyOjpzZWxlY3QoZXhwX3N1YmplY3RfaWQsIHB1bHNldW5kLCBtZWxvZHl1bmQsIGluc3RydW1lbnRhbHVuZCwgdGltYnJldW4sIHRlbXBvdW5kLCBpbnRlbnRpb25hbGl0eXVuZCwgaGFybW9ueXVuZCwgY29tcGxleGl0eXVuZCwgdG9uZXVuZCwgcmh5dGhtdW5kKSAlPiUKICBuYS5vbWl0KCkgJT4lCiAgZ3JvdXBfYnkoZXhwX3N1YmplY3RfaWQpICU+JQogIHN1bW1hcmlzZSh0b3RhbF91bmQgPSBzdW0oY19hY3Jvc3MocHVsc2V1bmQ6Y29tcGxleGl0eXVuZCkpKQoKdW5kZXJzdGFuZGluZ19wZXJmZWF0dXJlIDwtIGFsbF90YXNrcyAlPiUKICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCBwdWxzZXVuZCwgbWVsb2R5dW5kLCBpbnN0cnVtZW50YWx1bmQsIHRpbWJyZXVuLCB0ZW1wb3VuZCwgaW50ZW50aW9uYWxpdHl1bmQsIGhhcm1vbnl1bmQsIGNvbXBsZXhpdHl1bmQsIHRvbmV1bmQsIHJoeXRobXVuZCkgJT4lCiAgbmEub21pdCgpCgoKdW5kZXJzdGFuZGluZ19sb25nIDwtIHBpdm90X2xvbmdlcih1bmRlcnN0YW5kaW5nX3BlcmZlYXR1cmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xzID0gYyhwdWxzZXVuZCwgbWVsb2R5dW5kLCBpbnN0cnVtZW50YWx1bmQsIHRpbWJyZXVuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlbXBvdW5kLCBpbnRlbnRpb25hbGl0eXVuZCwgaGFybW9ueXVuZCwgY29tcGxleGl0eXVuZCwgdG9uZXVuZCwgcmh5dGhtdW5kKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlIikKCnVuZGVyc3RhbmRpbmcgPC0gbWVyZ2UodW5kZXJzdGFuZGluZywgYWxsX3NjYWxlcywgYnkgPSJleHBfc3ViamVjdF9pZCIpCgoKCmBgYAoKTGV0J3MgY29tcHV0ZSBob3cgb2Z0ZW4gcGFydGljaXBhbnRzIGxpc3RlbiB0byBkaWZmZXJlbnQgZ2VucmVzCgoKYGBge3J9CmdlbnJlcyA8LSBhbGxfdGFza3MgJT4lCiAgZmlsdGVyKHRhc2tfbmFtZSAlaW4lIGMoIkdlbnJlcyIsICJHZW5yZXMyIiwgIkdlbnJlczMiLCAiR2VucmVzNCIsICJHZW5yZXM1IiwgIkdlbnJlNiIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCB0b3A0MCwgcG9wLCByb2NrLCBjbGFzc2ljYWwsIG5vaXNlLCBleHBlcmltZW50YWwsIGVkbSkgCgpnZW5yZXNbaXMubmEoZ2VucmVzKV0gPC0gMAoKZ2VucmVzIDwtIGdlbnJlcyAlPiUKICBtdXRhdGUobXVzaWNfZGl2ZXJzaXR5ID0gbm9pc2UgKyBleHBlcmltZW50YWwsCiAgICAgICAgIG5vaXNlX2V4cGVyaW1lbnRhbF9saXN0ZW4gPSBpZmVsc2UoaXMubmEobXVzaWNfZGl2ZXJzaXR5KSwgIm5vIiwgInllcyIpKQpnZW5yZXMkbm9pc2VfZXhwZXJpbWVudGFsX2xpc3RlbiA8LSBhcy5mYWN0b3IoZ2VucmVzJG5vaXNlX2V4cGVyaW1lbnRhbF9saXN0ZW4pICAKCmFsbF9zY2FsZXMgPC0gYWxsX3NjYWxlcyAlPiUKICBsZWZ0X2pvaW4oZ2VucmVzICU+JQogICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoZXhwX3N1YmplY3RfaWQsIG11c2ljX2RpdmVyc2l0eSksCiAgICAgICAgICAgIGJ5ID0gImV4cF9zdWJqZWN0X2lkIikgIAoKCmBgYAoKCkNhbGN1bGF0ZSB0aGUgbWVhbiBhZ2UgYW5kIGdlbmRlciBpbmZvcm1hdGlvbgoKYGBge3J9CgptZWFuKGRlbW9fZGF0YSRhZ2UpCnNkKGRlbW9fZGF0YSRhZ2UpCm1pbihkZW1vX2RhdGEkYWdlKQptYXgoZGVtb19kYXRhJGFnZSkKCnRhYmxlKGRlbW9fZGF0YSRnZW5kZXIpCgpgYGAKClB1dCB0aGUgYXZlcmFnZSByYXRpbmcgZm9yIGVhY2ggcGFydGljaXBhbnQgdG8gdGhlIHNjYWxlcyBkZgpgYGB7cn0KCm1lYW5zX3NjYWxlcyA8LSBtZXJnZShhbGxfc2NhbGVzLCBwYXJ0aWNpcGFudF9tZWFucywgYnkgPSAiZXhwX3N1YmplY3RfaWQiKQoKbWVhbnNfc2NhbGVzX2FnZSA8LSBtZWFuc19zY2FsZXMgJT4lCiAgbGVmdF9qb2luKGRlbW9fZGF0YSAlPiUKICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCBhZ2UpLAogICAgICAgICAgICAgIGJ5ID0gImV4cF9zdWJqZWN0X2lkIikgCgptZWFuc19zY2FsZXNfYWdlX2dlbnJlcyA8LSBtZXJnZShtZWFuc19zY2FsZXNfYWdlLCBnZW5yZXMsIGJ5ID0gImV4cF9zdWJqZWN0X2lkIikKCmBgYAoKQSBERiBqdXN0IGZvciB0aGUgYW1iaWd1b3VzIHN0aW11bGkgCgpgYGB7cn0KYW1iaWd1b3VzX3N0aW11bGkgPC0gcmF0aW5ncyAlPiUKICBmaWx0ZXIobGFiZWwgPT0gImFtYmlndW91cyIpCgphbWJpZ3VvdXNfcGFydGljaXBhbnRfbWVhbnMgPC0gYW1iaWd1b3VzX3N0aW11bGkgJT4lCiAgZ3JvdXBfYnkoZXhwX3N1YmplY3RfaWQpICU+JQogIHN1bW1hcml6ZShtZWFuX21vbnJhID0gbWVhbihtb25yYSkpICU+JQogIGRwbHlyOjpzZWxlY3QoZXhwX3N1YmplY3RfaWQsIG1lYW5fbW9ucmEpCgpgYGAKCgpBIERGIGZvciB0aGUgZGVzY3JpcHRpdmUgc3RhdHMgZm9yIG1vbnJhIApgYGB7cn0KbW9ucmFfZGVzY19zdGF0cyA8LSByYXRpbmdzIHw+IAogIGdyb3VwX2J5KGF1ZGlvX25hbWUpIHw+IAogIHN1bW1hcml6ZShtZWFuX21vbnJhID0gbWVhbihtb25yYSksCiAgICAgICAgICAgIHNkX21vbnJhID0gc2QobW9ucmEpKSB8PiAKICBsZWZ0X2pvaW4oYXVkaW9fY2x1c3RlcnMgfD4gCiAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChhdWRpb19uYW1lLCBsYWJlbCksCiAgICAgICAgICAgIGJ5ID0gImF1ZGlvX25hbWUiKQoKbW9ucmFfZGVzY19zdGF0cyRsYWJlbCA8LSBmYWN0b3IobW9ucmFfZGVzY19zdGF0cyRsYWJlbCwgbGV2ZWxzID0gYygibm9uLW11c2ljIiwgImFtYmlndW91cyIsICJtdXNpYyIpKQoKYGBgCgoKQ2lyY3VsYXIgY2x1c3RlciBwbG90IGZvciB0aGUgcGFwZXIsIGluY2x1ZGVkIGluIEZpZ3VyZSAyQQpgYGB7cn0KIyBSZW9yZGVyIHRoZSBhdWRpb19uYW1lIGJhc2VkIG9uIHRoZSBsYWJlbCB0byBncm91cCB0aGUgY2x1c3RlcnMKYXVkaW9fY2x1c3RlcnMgPC0gYXVkaW9fY2x1c3RlcnNbb3JkZXIoYXVkaW9fY2x1c3RlcnMkbGFiZWwpLCBdCgphdWRpb19jbHVzdGVycyRhdWRpb19uYW1lIDwtIGFzLmNoYXJhY3RlcihhdWRpb19jbHVzdGVycyRhdWRpb19uYW1lKQoKIyBTdGVwIDE6IE9yZGVyIHRoZSBkYXRhZnJhbWUgYWxwaGFiZXRpY2FsbHkgaW5jbHVkaW5nIHByZWZpeGVzCmF1ZGlvX2NsdXN0ZXJzIDwtIGF1ZGlvX2NsdXN0ZXJzICU+JQogIGFycmFuZ2UoYXVkaW9fbmFtZSkgCmF1ZGlvX2NsdXN0ZXJzJG51bWJlciA8LSAxOm5yb3coYXVkaW9fY2x1c3RlcnMpICAjIEFzc2lnbiBudW1iZXJzIHNlcXVlbnRpYWxseQoKCmF1ZGlvX2NsdXN0ZXJzIDwtIGF1ZGlvX2NsdXN0ZXJzICU+JQogIG11dGF0ZShjbGVhbl9uYW1lcyA9IHN0cl9yZXBsYWNlKGF1ZGlvX25hbWUsICdeKC4rKVxcLm1wMyQnLCAnXFwxJykpICU+JQogIG11dGF0ZShjbGVhbl9uYW1lcyA9IHN0cl90b190aXRsZShjbGVhbl9uYW1lcykpCgoKZGlzdGFuY2VfbWF0IDwtIGRpc3QoYXVkaW9fZGVzY3JpcHRpdmVzJG1lYW5fbW9ucmEsIG1ldGhvZCA9ICdldWNsaWRlYW4nKQpkaXN0YW5jZV9tYXQKCiMgRml0dGluZyBIaWVyYXJjaGljYWwgY2x1c3RlcmluZyBNb2RlbCB0byB0cmFpbmluZyBkYXRhc2V0CnNldC5zZWVkKDI0MCkgIyBTZXR0aW5nIHNlZWQKSGllcmFyX2NsIDwtIGhjbHVzdChkaXN0YW5jZV9tYXQsIG1ldGhvZCA9ICJhdmVyYWdlIikKCgojIEFzc3VtaW5nICdIaWVyYXJfY2wnIGlzIHlvdXIgaGNsdXN0IHJlc3VsdCBhbmQgJ2ZpdCcgY29udGFpbnMgY2x1c3RlciBhc3NpZ25tZW50cwpwaHlsb190cmVlIDwtIGFzLnBoeWxvKEhpZXJhcl9jbCkgICMgQ29udmVydCBoY2x1c3QgdG8gcGh5bG8gb2JqZWN0CmZpdCA8LSBjdXRyZWUoSGllcmFyX2NsLCBrID0gMykKCiMgRGVmaW5lIHlvdXIgY2x1c3RlciBjb2xvcnMKIyBFbnN1cmUgJ2ZpdCcgaXMgYSB2ZWN0b3IgY29udGFpbmluZyBjbHVzdGVyIGFzc2lnbm1lbnRzIGZvciBlYWNoIHRpcApjb2xvcnMgPC0gYygicmVkIiwgImJsdWUiLCAiZ3JlZW4iKSAgIyAxID0gcmVkLCAyID0gYmx1ZSwgMyA9IGdyZWVuCnRpcF9jb2xvcnMgPC0gY29sb3JzW2ZpdF0gICMgTWFwIHRoZSBjbHVzdGVyIGFzc2lnbm1lbnRzIHRvIGNvbG9ycwoKIyBQbG90IHRoZSBjaXJjdWxhciBkZW5kcm9ncmFtIHdpdGggY29sb3ItY29kZWQgdGlwcwpwbG90KHBoeWxvX3RyZWUsIAogICAgIHR5cGUgPSAiZmFuIiwgICAgICAgIyBDaXJjdWxhciBwbG90CiAgICAgdGlwLmNvbG9yID0gdGlwX2NvbG9ycywgICMgQ29sb3IgdGlwcyBiYXNlZCBvbiBjbHVzdGVycwogICAgIGxhYmVsLm9mZnNldCA9IDAuMDEsICAjIFNwYWNlIGJldHdlZW4gdGlwcyBhbmQgbGFiZWxzCiAgICAgY2V4ID0gMS42LCAgICAgICAgICAgIyBUZXh0IHNpemUKICAgICBzaG93LnRpcC5sYWJlbCA9IFRSVUUpICAjIFNob3cgbGFiZWxzIChhdWRpbyBuYW1lcykKCgojIERlZmluZSBjb2xvcnMgZm9yIGVhY2ggY2x1c3RlcgpsYWJlbF9jb2xvcnMgPC0gYygibXVzaWMiID0gInJlZCIsICJhbWJpZ3VvdXMiID0gImJsdWUiLCAibm9uLW11c2ljIiA9ICJncmVlbiIpCgojIENyZWF0ZSBhIGJsYW5rIHBsb3QgZm9yIHByaW50aW5nIHRoZSB0ZXh0CmdyaWQubmV3cGFnZSgpCgojIFNldCB1cCB0aGUgY29sdW1uIHBvc2l0aW9ucwp4X3Bvc2l0aW9ucyA8LSBjKDAuMSwgMC40LCAwLjcpICAjIFggY29vcmRpbmF0ZXMgZm9yIHRoZSAzIGNvbHVtbnMKCiMgTG9vcCB0aHJvdWdoIGVhY2ggcm93IGFuZCBhc3NpZ24gdGV4dCB0byB0aGUgY29ycmVjdCBjb2x1bW4gYW5kIHJvdyBwb3NpdGlvbgpmb3IgKGkgaW4gMTpucm93KGF1ZGlvX2NsdXN0ZXJzKSkgewogICMgRGV0ZXJtaW5lIHRoZSBjb2x1bW4gKDFzdCwgMm5kLCBvciAzcmQgY29sdW1uKQogIGNvbHVtbiA8LSAoKGkgLSAxKSAlLyUgMzApICsgMQogIHJvdyA8LSAoaSAtIDEpICUlIDMwICsgMQogIAogICMgQ2FsY3VsYXRlIHRoZSB5IHBvc2l0aW9uIGZvciBlYWNoIHJvdyAoaW52ZXJ0IHJvdyBpbmRleCBmb3IgZ3JpZCBwb3NpdGlvbmluZykKICB5X3Bvc2l0aW9uIDwtIDEgLSAocm93ICogMC4wMykgICMgQWRqdXN0IHNwYWNpbmcgYmV0d2VlbiByb3dzCgogICMgUHJpbnQgdGhlIHRleHQgaW4gdGhlIGNvcnJlY3QgY29sdW1uLCBjb2xvci1jb2RlZCBieSBjbHVzdGVyCiAgZ3JpZC50ZXh0KAogICAgbGFiZWwgPSBwYXN0ZShhdWRpb19jbHVzdGVycyRudW1iZXJbaV0sICItIiwgYXVkaW9fY2x1c3RlcnMkY2xlYW5fbmFtZXNbaV0pLCAKICAgIHggPSB4X3Bvc2l0aW9uc1tjb2x1bW5dLCAKICAgIHkgPSB5X3Bvc2l0aW9uLCAKICAgIGdwID0gZ3Bhcihjb2wgPSBsYWJlbF9jb2xvcnNbYXVkaW9fY2x1c3RlcnMkbGFiZWxbaV1dLCBmb250c2l6ZSA9IDIwKSwKICAgIGp1c3QgPSAibGVmdCIKICApCn0KICAKCgoKICAgCmBgYAoKUGxvdHRpbmcgdGhlIHBhcnRpY2lwYW50cyBhbmQgYXVkaW9zIG9yZGVyZWQgYnkgbWVhbiAoRmlndXJlIDJCKQoKVGhlIGZpcnN0IGNvbHVtbiByZXByZXNlbnQgdGhlIG1lYW4gbXVzaWMgcmF0aW5ncyBvcmRlcmVkIGZyb20gaGlnaCAob24gdG9wKSB0byBsb3cgKG9uIHRoZSBib3R0b20pLiBUaGVuLCBldmVyeSBvdGhlciBjb2x1bW4gaXMgdGhlIHJhbmtpbmcgb2YgZWFjaCBwYXJ0aWNpcGFudCdzIG11c2ljIHJhdGluZ3MuCgpgYGB7cn0KI0RvIHRoaXMgb3RoZXJ3aXNlIGl0IG92ZXJyaWRlcyBkcGx5cgpkZXRhY2goInBhY2thZ2U6dGlkeXRhYmxlIiwgdW5sb2FkID0gVFJVRSkKCgojIFJlc2hhcGluZyB0aGUgZGF0YWZyYW1lCm1vbnJhX21tMV9sb25nIDwtIG1vbnJhX21tMSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gLWV4cF9zdWJqZWN0X2lkLCAgIyBLZWVwIGV4cF9zdWJqZWN0X2lkLCBnYXRoZXIgb3RoZXIgY29sdW1ucwogICAgbmFtZXNfdG8gPSAiYXVkaW9fbmFtZSIsICAjIFRoZSBuYW1lcyBvZiB0aGUgYXVkaW8gY29sdW1ucyB3aWxsIGdvIHRvIHRoaXMgbmV3IGNvbHVtbgogICAgdmFsdWVzX3RvID0gInJhdGluZyIgICAgICAjIFRoZSByYXRpbmdzIHdpbGwgZ28gdG8gdGhpcyBuZXcgY29sdW1uCiAgKQoKIyBOb3cgcGl2b3Qgd2lkZXIgc28gdGhhdCBleHBfc3ViamVjdF9pZCBiZWNvbWVzIGNvbHVtbnMKbW9ucmFfbW0xX3dpZGUgPC0gbW9ucmFfbW0xX2xvbmcgJT4lCiAgcGl2b3Rfd2lkZXIoCiAgICBuYW1lc19mcm9tID0gZXhwX3N1YmplY3RfaWQsICAjIFRoZSBleHBfc3ViamVjdF9pZCB2YWx1ZXMgYmVjb21lIG5ldyBjb2x1bW5zCiAgICB2YWx1ZXNfZnJvbSA9IHJhdGluZyAgICAgICAgICAjIFZhbHVlcyBjb21lIGZyb20gdGhlIHJhdGluZyBjb2x1bW4KICApCgojIFByaW50IHRoZSByZXNoYXBlZCBkYXRhZnJhbWUKcHJpbnQobW9ucmFfbW0xX3dpZGUpCgptb25yYV9tZWFuX3BhcnRpY2lwYW50cyA8LSBtb25yYV9tbTFfd2lkZSAlPiUKICBsZWZ0X2pvaW4oYXVkaW9fZGVzY3JpcHRpdmVzICU+JSBkcGx5cjo6c2VsZWN0KGF1ZGlvX25hbWUsIG1lYW5fbW9ucmEpLCBieSA9ICJhdWRpb19uYW1lIikgJT4lCiAgcmVsb2NhdGUobWVhbl9tb25yYSwgLmFmdGVyID0gYXVkaW9fbmFtZSkgJT4lCiAgbGVmdF9qb2luKGF1ZGlvX2NsdXN0ZXJzICU+JSBkcGx5cjo6c2VsZWN0KGF1ZGlvX25hbWUsIGxhYmVsKSwgYnkgPSAiYXVkaW9fbmFtZSIpICU+JQogIHJlbG9jYXRlKGxhYmVsLCAuYWZ0ZXIgPSBtZWFuX21vbnJhKQoKIyBTdGVwIDE6IFJlc2hhcGUgdGhlIG9yaWdpbmFsIGRhdGEgdG8gbG9uZyBmb3JtYXQgZm9yIHBhcnRpY2lwYW50IHJhdGluZ3MKbG9uZ19kYXRhIDwtIG1vbnJhX21lYW5fcGFydGljaXBhbnRzICU+JQogIHBpdm90X2xvbmdlcigKICAgIGNvbHMgPSAtYyhhdWRpb19uYW1lLCBtZWFuX21vbnJhLCBsYWJlbCksICAjIEV4Y2x1ZGUgbm9uLXBhcnRpY2lwYW50IGNvbHVtbnMKICAgIG5hbWVzX3RvID0gInBhcnRpY2lwYW50X2lkIiwgCiAgICB2YWx1ZXNfdG8gPSAicmF0aW5nIgogICkgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnRfaWQpICU+JQogIGFycmFuZ2UocmF0aW5nLCAuYnlfZ3JvdXAgPSBUUlVFKSAlPiUKICBtdXRhdGUocmFuayA9IHJvd19udW1iZXIoKSkgICMgQXNzaWduIHJhbmsgYmFzZWQgb24gdGhlIG9yZGVyIG9mIHJhdGluZ3Mgd2l0aGluIGVhY2ggcGFydGljaXBhbnQKCiMgU3RlcCAyOiBDcmVhdGUgYSBsb25nIGZvcm1hdCBmb3IgbWVhbl9tb25yYQptZWFuX21vbnJhX2xvbmcgPC0gbW9ucmFfbWVhbl9wYXJ0aWNpcGFudHMgJT4lCiAgZHBseXI6OnNlbGVjdChhdWRpb19uYW1lLCBtZWFuX21vbnJhLCBsYWJlbCkgJT4lCiAgbXV0YXRlKHBhcnRpY2lwYW50X2lkID0gIm1lYW5fbW9ucmEiLCByYXRpbmcgPSBtZWFuX21vbnJhKSAlPiUKICBkcGx5cjo6c2VsZWN0KGF1ZGlvX25hbWUsIHBhcnRpY2lwYW50X2lkLCByYXRpbmcsIGxhYmVsKQoKIyBTdGVwIDM6IENvbWJpbmUgYm90aCBsb25nIGZvcm1hdHMKY29tYmluZWRfbG9uZ19kYXRhIDwtIGJpbmRfcm93cyhsb25nX2RhdGEsIG1lYW5fbW9ucmFfbG9uZykKCiMgU3RlcCA0OiBBZGp1c3QgdGhlIHBhcnRpY2lwYW50X2lkIHRvIG1ha2UgbWVhbl9tb25yYSBmaXJzdApjb21iaW5lZF9sb25nX2RhdGEgPC0gY29tYmluZWRfbG9uZ19kYXRhICU+JQogIG11dGF0ZShwYXJ0aWNpcGFudF9pZCA9IGZhY3RvcihwYXJ0aWNpcGFudF9pZCwgbGV2ZWxzID0gYygibWVhbl9tb25yYSIsIHVuaXF1ZShsb25nX2RhdGEkcGFydGljaXBhbnRfaWQpKSkpICAjIEVuc3VyZXMgbWVhbl9tb25yYSBpcyBmaXJzdAoKIyBTdGVwIDU6IFJhbmsgdGhlIGNvbWJpbmVkIGRhdGEKY29tYmluZWRfbG9uZ19kYXRhIDwtIGNvbWJpbmVkX2xvbmdfZGF0YSAlPiUKICBncm91cF9ieShwYXJ0aWNpcGFudF9pZCkgJT4lCiAgYXJyYW5nZShyYXRpbmcsIC5ieV9ncm91cCA9IFRSVUUpICU+JQogIG11dGF0ZShyYW5rID0gcm93X251bWJlcigpKSAgIyBBc3NpZ24gcmFuayBmb3IgYWxsIHBhcnRpY2lwYW50cyBpbmNsdWRpbmcgbWVhbl9tb25yYQoKIyBTdGVwIDY6IENyZWF0ZSB0aGUgcGxvdApnZ3Bsb3QoY29tYmluZWRfbG9uZ19kYXRhLCBhZXMoeCA9IHBhcnRpY2lwYW50X2lkLCB5ID0gcmFuaywgZmlsbCA9IGxhYmVsKSkgKwogIGdlb21fdGlsZSgpICsKICBzY2FsZV9maWxsX21hbnVhbCgKICAgIHZhbHVlcyA9IGMoIm11c2ljIiA9ICJyZWQiLCAiYW1iaWd1b3VzIiA9ICJibHVlIiwgIm5vbi1tdXNpYyIgPSAiZ3JlZW4iKSwKICAgIGxhYmVscyA9IGMoIm11c2ljIiA9ICJNdXNpYyIsICJhbWJpZ3VvdXMiID0gIkFtYmlndW91cyIsICJub24tbXVzaWMiID0gIk5vdC1tdXNpYyIpCiAgKSArCiAgbGFicygKICAgIHggPSAiUGFydGljaXBhbnRzIiwKICAgIHkgPSAiUmFua2luZyBvZiBTdGltdWxpIiwKICAgIHRpdGxlID0gIiAiLAogICAgZmlsbCA9ICJDbHVzdGVyIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwKSwKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksCiAgICBheGlzLnRleHQueC5sZWZ0ID0gZWxlbWVudF90ZXh0KAogICAgICBpZmVsc2UodW5pcXVlKGNvbWJpbmVkX2xvbmdfZGF0YSRwYXJ0aWNpcGFudF9pZCkgPT0gIm1lYW5fbW9ucmEiLCAiYmxhY2siLCAidHJhbnNwYXJlbnQiKQogICAgKQogICkKCgpgYGAKCgoKCkV4cGVyaW1lbnQgNCBBbmFseXNlcwoKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygiaXJyIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJsbWVyVGVzdCIpCiMgaW5zdGFsbC5wYWNrYWdlcygiTXVNSW4iKQojIGluc3RhbGwucGFja2FnZXMoImZhY3RvZXh0cmEiKQojIGluc3RhbGwucGFja2FnZXMoInNpbXIiKQojIGluc3RhbGwucGFja2FnZXMoImNhciIpCiMgaW5zdGFsbC5wYWNrYWdlcygic2pQbG90IikKIyBpbnN0YWxsLnBhY2thZ2VzKCJnZ3NpZ25pZiIpCiMgaW5zdGFsbC5wYWNrYWdlcygiZ3JpZEV4dHJhIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJlbW1lYW5zIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJnZ3JhZGFyIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJmbXNiIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJlZmZlY3RzIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJubmV0IikKIyBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJtdWx0Y29tcCIpCiMgaW5zdGFsbC5wYWNrYWdlcygiZ2dzaWduaWYiKQojIGluc3RhbGwucGFja2FnZXMoImdncmVwZWwiKQojICNpbnN0YWxsLnBhY2thZ2VzKCJnZ3JhZGFyIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJlZmZlY3RzIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJwb0xDQSIpCiMgaW5zdGFsbC5wYWNrYWdlcygibGNtbSIpCiMgaW5zdGFsbC5wYWNrYWdlcygibWNsdXN0IikKIyBpbnN0YWxsLnBhY2thZ2VzKCJyY29tcGFuaW9uIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJwc2NsIikKI2luc3RhbGwucGFja2FnZXMoIm9yZGluYWwiKQoKb3B0aW9ucyhzY2lwZW49OTk5KQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShjYXIpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoY29ycnBsb3QpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZHBseXIpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZWZmZWN0cykpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShlbW1lYW5zKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGZhY3RvZXh0cmEpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZm1zYikpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShnZ3JlcGVsKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGdnc2lnbmlmKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGdyaWRFeHRyYSkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShpcnIpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkobGNtbSkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShsbWU0KSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGxtZXJUZXN0KSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KE1BU1MpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkobWNsdXN0KSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KE11TUluKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KG11bHRjb21wKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KG5uZXQpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkob3JkaW5hbCkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShwb0xDQSkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShwc2NsKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHJjb21wYW5pb24pKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoc2ltcikpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShzalBsb3QpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkodGlkeXIpKSkKCgpgYGAKCgpgYGB7cn0KYXVkaW9fZGVzY3JpcHRpdmVzIDwtIHJlYWRfZXhjZWwoImF1ZGlvX2Rlc2NyaXB0aXZlcy54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gIlNoZWV0MSIpCgptb25yYV9kYXRhIDwtIHJlYWRfZXhjZWwoIm1vbnJhX2RhdGEueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9ICJTaGVldDEiKQoKYGBgCgoKTU0xIGZvciBtb25yYQoKT3ZlcmFsbCBNTTEgdmFsdWUgZm9yIG11c2ljIHJhdGluZ3MgaXMgLjg3LiBUaGlzIGlzIHZlcnkgaGlnaCwgc28gcGFydGljaXBhbnRzIHRvIGFncmVlIHdpdGggZWFjaCBvdGhlci4gVGhpcyBpcyByZXBvcnRlZCBpbiB0aGUgcGFwZXIuCgpgYGB7cn0KCk1NMV9yZXZpc2VkIDwtIGZ1bmN0aW9uKGRmKXsKICAjc2F2ZSAmIHJlbW92ZSBzdWJqIGlkCiAgaWQgPC0gZGZbLCAxXQogIGRmIDwtIGFzLm1hdHJpeChkZlssLTFdKQogIAogICNDb21wdXRlIG1lYW5zIG1pbnVzIG9uZQogIG1lYW5zIDwtIG1hdHJpeCgwLCBucm93ID0gbnJvdyhkZiksIG5jb2wgPSBuY29sKGRmKSkKICBmb3IoaiBpbiAxOm5yb3coZGYpKXsKICAgIG1lYW5zW2osXSA8LSBjb2xNZWFucyhkZlstaixdKQogIH0KICAKICAjQ29tcHV0ZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiBtZWFucyBtaW51cyBvbmVzIGFuZCBvbmVzIHJhdGluZ3MKICBtbTEgPC0gc2FwcGx5KDE6bnJvdyhkZiksIGZ1bmN0aW9uKC54KSBjb3IoZGZbLngsXSwgbWVhbnNbLngsXSkpCiAgCiAgI3RyYW5zZm9ybSBjb3JyZWxhdGlvbnMgaW50byB6IHNjb3JlcyAociB0byB6IEZpc2hlcikKICB6X3Njb3JlcyA8LSBzYXBwbHkobW0xLCBmdW5jdGlvbih4KSBsb2coKDEgKyB4KS8oMSAtIHgpKSkgKiAuNSAKICAKICAjc2F2ZSBhdmVyYWdlIGNvcnJlbGF0aW9uICh6IGF2ZXJhZ2UgdG8gciBhdmVyYWdlIEZpc2hlcikgYW5kIGNvcnJlbGF0aW9ucyBwZXIgcmF0ZXIKICByZXN1bHQgPC0gIGxpc3QoTU0xID0gKGV4cCgyICogKG1lYW4oel9zY29yZXMpKSkgLSAxKS8oZXhwKCAyICogKG1lYW4oel9zY29yZXMpKSkgKyAxKSwgCiAgICAgICAgICAgICAgICAgIHJhdyA9IGRhdGEuZnJhbWUoaWQsIG1tMSA9IG1tMSwgbW0xX3ogPSB6X3Njb3JlcykpCiAgcmVzdWx0Cn0KCiNJIHdhbnRlZCB0byBzZWUgdGhlIE1NMSBsaXN0IHBscwpNTTFfTGlzdCA8LSBNTTFfcmV2aXNlZChtb25yYV9tbTEpCgpNTTFfTCA8LSBhcy5kYXRhLmZyYW1lKE1NMV9MaXN0JHJhdykKCk1NMV9MaXN0CgpNTTFfTGlzdCRNTTEKYGBgCgoKTU0xIGZvciBlYWNoIGZlYXR1cmVzIChSZXBvcnRlZCkKClRoaXMgdmFyaWVzLi4uIEZvciBoaWdoZXIgbGV2ZWwgZmVhdHVyZXMsIHRoZXJlIGlzIG1vcmUgYWdyZWVtZW50LCBmb3IgbG93ZXIgbGV2ZWwgZmVhdHVyZXMsIHRoZXJlIGlzIGxlc3MuLi4KCmBgYHtyfQoKTU0xX3JlcGV0aXRpb24gPC0gTU0xX3JldmlzZWQocmVwZXRpdGlvbl9tbTEpCk1NMV9yZXBldGl0aW9uJE1NMQoKTU0xX3B1bHNlIDwtIE1NMV9yZXZpc2VkKHB1bHNlX21tMSkKTU0xX3B1bHNlJE1NMQoKTU0xX3JoeXRobSA8LSBNTTFfcmV2aXNlZChyaHl0aG1fbW0xKQpNTTFfcmh5dGhtJE1NMQoKTU0xX21lbG9keSA8LSBNTTFfcmV2aXNlZChtZWxvZHlfbW0xKQpNTTFfbWVsb2R5JE1NMQoKTU0xX2luc3RydW1lbnRhbCA8LSBNTTFfcmV2aXNlZChpbnN0cnVtZW50YWxfbW0xKQpNTTFfaW5zdHJ1bWVudGFsJE1NMQoKTU0xX3RpbWJyZSA8LSBNTTFfcmV2aXNlZCh0aW1icmVfbW0xKQpNTTFfdGltYnJlJE1NMQoKTU0xX3RlbXBvIDwtIE1NMV9yZXZpc2VkKHRlbXBvX21tMSkKTU0xX3RlbXBvJE1NMQoKTU0xX2ludGVudGlvbmFsaXR5IDwtIE1NMV9yZXZpc2VkKGludGVudGlvbmFsaXR5X21tMSkKTU0xX2ludGVudGlvbmFsaXR5JE1NMQoKTU0xX2hhcm1vbnkgPC0gTU0xX3JldmlzZWQoaGFybW9ueV9tbTEpCk1NMV9oYXJtb255JE1NMQoKTU0xX2NvbXBsZXhpdHkgPC0gTU0xX3JldmlzZWQoY29tcGxleGl0eV9tbTEpCk1NMV9jb21wbGV4aXR5JE1NMQoKCmBgYAoKCktyaXBwZW5kb3JmZidzIGFscGhhIGZvciBlYWNoIHJhdGluZywgYXQgdGhlIGdyb3VwIGxldmVsLiAoUmVwb3J0ZWQpCgpgYGB7cn0KCm1vbnJhX2tyaXAgPC0gbW9ucmFfbW0xICU+JQogIGRwbHlyOjpzZWxlY3QoIWV4cF9zdWJqZWN0X2lkKQoKbW9ucmFfa3JpcCA8LSBhcy5tYXRyaXgobW9ucmFfa3JpcCkKCmtyaXBwLmFscGhhKG1vbnJhX2tyaXAsIG1ldGhvZCA9ICJpbnRlcnZhbCIpCgoKaW50ZW50aW9uYWxpdHlfa3JpcCA8LSBpbnRlbnRpb25hbGl0eV9tbTEgJT4lCiAgZHBseXI6OnNlbGVjdCghZXhwX3N1YmplY3RfaWQpCgppbnRlbnRpb25hbGl0eV9rcmlwIDwtIGFzLm1hdHJpeChpbnRlbnRpb25hbGl0eV9rcmlwKQoKa3JpcHAuYWxwaGEoaW50ZW50aW9uYWxpdHlfa3JpcCwgbWV0aG9kID0gImludGVydmFsIikKCgoKaW5zdHJ1bWVudGFsX2tyaXAgPC0gaW5zdHJ1bWVudGFsX21tMSAlPiUKICBkcGx5cjo6c2VsZWN0KCFleHBfc3ViamVjdF9pZCkKCmluc3RydW1lbnRhbF9rcmlwIDwtIGFzLm1hdHJpeChpbnN0cnVtZW50YWxfa3JpcCkKCmtyaXBwLmFscGhhKGluc3RydW1lbnRhbF9rcmlwLCBtZXRob2QgPSAiaW50ZXJ2YWwiKQoKCmNvbXBsZXhpdHlfa3JpcCA8LSBjb21wbGV4aXR5X21tMSAlPiUKICBkcGx5cjo6c2VsZWN0KCFleHBfc3ViamVjdF9pZCkKCmNvbXBsZXhpdHlfa3JpcCA8LSBhcy5tYXRyaXgoY29tcGxleGl0eV9rcmlwKQoKa3JpcHAuYWxwaGEoY29tcGxleGl0eV9rcmlwLCBtZXRob2QgPSAiaW50ZXJ2YWwiKQoKCnJlcGV0aXRpb25fa3JpcCA8LSByZXBldGl0aW9uX21tMSAlPiUKICBkcGx5cjo6c2VsZWN0KCFleHBfc3ViamVjdF9pZCkKCnJlcGV0aXRpb25fa3JpcCA8LSBhcy5tYXRyaXgocmVwZXRpdGlvbl9rcmlwKQoKa3JpcHAuYWxwaGEocmVwZXRpdGlvbl9rcmlwLCBtZXRob2QgPSAiaW50ZXJ2YWwiKQoKCm1lbG9keV9rcmlwIDwtIG1lbG9keV9tbTEgJT4lCiAgZHBseXI6OnNlbGVjdCghZXhwX3N1YmplY3RfaWQpCgptZWxvZHlfa3JpcCA8LSBhcy5tYXRyaXgobWVsb2R5X2tyaXApCgprcmlwcC5hbHBoYShtZWxvZHlfa3JpcCwgbWV0aG9kID0gImludGVydmFsIikKCgpyaHl0aG1fa3JpcCA8LSByaHl0aG1fbW0xICU+JQogIGRwbHlyOjpzZWxlY3QoIWV4cF9zdWJqZWN0X2lkKQoKcmh5dGhtX2tyaXAgPC0gYXMubWF0cml4KHJoeXRobV9rcmlwKQoKa3JpcHAuYWxwaGEocmh5dGhtX2tyaXAsIG1ldGhvZCA9ICJpbnRlcnZhbCIpCgoKaGFybW9ueV9rcmlwIDwtIGhhcm1vbnlfbW0xICU+JQogIGRwbHlyOjpzZWxlY3QoIWV4cF9zdWJqZWN0X2lkKQoKaGFybW9ueV9rcmlwIDwtIGFzLm1hdHJpeChoYXJtb255X2tyaXApCgprcmlwcC5hbHBoYShoYXJtb255X2tyaXAsIG1ldGhvZCA9ICJpbnRlcnZhbCIpCgoKdGltYnJlX2tyaXAgPC0gdGltYnJlX21tMSAlPiUKICBkcGx5cjo6c2VsZWN0KCFleHBfc3ViamVjdF9pZCkKCnRpbWJyZV9rcmlwIDwtIGFzLm1hdHJpeCh0aW1icmVfa3JpcCkKCmtyaXBwLmFscGhhKHRpbWJyZV9rcmlwLCBtZXRob2QgPSAiaW50ZXJ2YWwiKQoKCnRlbXBvX2tyaXAgPC0gdGVtcG9fbW0xICU+JQogIGRwbHlyOjpzZWxlY3QoIWV4cF9zdWJqZWN0X2lkKQoKdGVtcG9fa3JpcCA8LSBhcy5tYXRyaXgodGVtcG9fa3JpcCkKCmtyaXBwLmFscGhhKHRlbXBvX2tyaXAsIG1ldGhvZCA9ICJpbnRlcnZhbCIpCgoKcHVsc2Vfa3JpcCA8LSBwdWxzZV9tbTEgJT4lCiAgZHBseXI6OnNlbGVjdCghZXhwX3N1YmplY3RfaWQpCgpwdWxzZV9rcmlwIDwtIGFzLm1hdHJpeChwdWxzZV9rcmlwKQoKa3JpcHAuYWxwaGEocHVsc2Vfa3JpcCwgbWV0aG9kID0gImludGVydmFsIikKCgoKYGBgCgoKTGluZWFyIE1peGVkIEVmZmVjdHMgTW9kZWwgdG8gcHJlZGljdCBNb05SYSBieSBwZXJjZXB0dWFsIGZlYXR1cmVzIChyZXBvcnRlZCkKCmBgYHtyfQpyYXRpbmdzJGF1ZGlvX25hbWUgPC0gYXMuZmFjdG9yKHJhdGluZ3MkYXVkaW9fbmFtZSkKcmF0aW5ncyRleHBfc3ViamVjdF9pZCA8LSBhcy5mYWN0b3IocmF0aW5ncyRleHBfc3ViamVjdF9pZCkKcmF0aW5ncyRsYWJlbCA8LSBmYWN0b3IocmF0aW5ncyRsYWJlbCwgbGV2ZWxzID0gYygibm9uLW11c2ljIiwgImFtYmlndW91cyIsICJtdXNpYyIpKQpyYXRpbmdzX2xvbmckbGFiZWwgPC0gZmFjdG9yKHJhdGluZ3NfbG9uZyRsYWJlbCwgbGV2ZWxzID0gYygibm9uLW11c2ljIiwgImFtYmlndW91cyIsICJtdXNpYyIpKQpyYXRpbmdzX2xvbmckdmFyaWFibGUgPC0gZmFjdG9yKHJhdGluZ3NfbG9uZyR2YXJpYWJsZSwgbGV2ZWxzID0gYygibW9ucmEiLCAidGltYnJlIiwgInRlbXBvIiwgInB1bHNlIiwgInJlcGV0aXRpb24iLCAiaGFybW9ueSIsICJyaHl0aG0iLCAibWVsb2R5IiwgImNvbXBsZXhpdHkiLCAiaW5zdHJ1bWVudGFsIiwgImludGVudGlvbmFsaXR5IikpCgpudWxsX21vZGVsIDwtIGxtZXIobW9ucmEgfiAxICsgKDEgfCBleHBfc3ViamVjdF9pZCkgKyAoMSB8IGF1ZGlvX25hbWUpLCBkYXRhID0gcmF0aW5ncykKCnBlcmNlcHR1YWxfbW9kZWwgPC0gbG1lcihtb25yYSB+IGludGVudGlvbmFsaXR5ICsgaW5zdHJ1bWVudGFsICsgY29tcGxleGl0eSArIHJlcGV0aXRpb24gKyBtZWxvZHkgKyBoYXJtb255ICsgcmh5dGhtICsgdGltYnJlICsgdGVtcG8gKyBwdWxzZSArICgxIHwgZXhwX3N1YmplY3RfaWQpICsgKDEgfCBhdWRpb19uYW1lKSwgZGF0YSA9IHJhdGluZ3MpCgpzdW1tYXJ5KHBlcmNlcHR1YWxfbW9kZWwpCnIuc3F1YXJlZEdMTU0ocGVyY2VwdHVhbF9tb2RlbCkKY2FyOjp2aWYocGVyY2VwdHVhbF9tb2RlbCkgCnJhbmQocGVyY2VwdHVhbF9tb2RlbCkKcGVyZm9ybWFuY2U6OmljYyhwZXJjZXB0dWFsX21vZGVsLCBieV9ncm91cCA9IFRSVUUpCgphbm92YShudWxsX21vZGVsLCBwZXJjZXB0dWFsX21vZGVsKQoKcmVzaWR1YWxzX3BlcmNlcHR1YWwgPC0gcmVzaWR1YWxzKHBlcmNlcHR1YWxfbW9kZWwpCmhpc3QocmVzaWR1YWxzX3BlcmNlcHR1YWwpCgpzalBsb3Q6OnBsb3RfbW9kZWwocGVyY2VwdHVhbF9tb2RlbCwgc2hvdy52YWx1ZXM9VFJVRSwgc2hvdy5wPVRSVUUsICN0eXBlID0gInN0ZCIsCiAgICAgICAgICAgICAgICAgICB2bGluZS5jb2xvciA9ICJncmF5IiwgdmFsdWUuc2l6ZSA9IDUpICsKICB5bGltKC0wLjAyLDAuMikgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMjApICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICIgIgogICkKCmBgYAoKCkFDT1VTVElDIEZFQVRVUkUgU0VMRUNUSU9OCgoKR2V0IGFuZCBwcmVwYXJlIGRhdGE6CmBgYHtyfQoKb3B0aW9ucyhzY2lwZW49OTk5KQoKI1RoZSBmZWF0dXJlcyBoYXZlIGJlZW4gZXh0cmFjdGVkIGFscmVhZHksIHdlIHJlYWQgaW4gdGhlIGRhdGEKCmFjb3VzdGljc19taXI8LSByZWFkX2V4Y2VsKCJlc3NlbnRpYV9hY291c3RpY3NfMi54bHN4IiwKICAgIHNoZWV0ID0gIlNoZWV0MSIpIAoKIyBXZSBjbGVhbiB0aGUgbmFtZXMKCmFjb3VzdGljc19taXIkYXVkaW9fbmFtZSA8LSBzdWIoIlxcLm1wMy4qIiwgIi5tcDMiLCBhY291c3RpY3NfbWlyJGF1ZGlvX25hbWUpCgojIEdldCB0aGUgY29sdW1uIG5hbWVzCmNvbF9uYW1lcyA8LSBjb2xuYW1lcyhhY291c3RpY3NfbWlyKQpjb2xfbmFtZXMKCiMgUmVtb3ZlICIiIGZyb20gdGhlIGVuZCBvZiBlYWNoIGNvbHVtbiBuYW1lCmNsZWFuX2NvbF9uYW1lcyA8LSBnc3ViKCciIiQnLCAnJywgY29sX25hbWVzKQoKIyBBc3NpZ24gdGhlIGNsZWFuZWQgY29sdW1uIG5hbWVzIGJhY2sgdG8gdGhlIGRhdGFmcmFtZQpjb2xuYW1lcyhhY291c3RpY3NfbWlyKSA8LSBjbGVhbl9jb2xfbmFtZXMKCiMgQ2hlY2sgdGhlIGNsZWFuZWQgY29sdW1uIG5hbWVzCnByaW50KGNvbG5hbWVzKGFjb3VzdGljc19taXIpKQoKYWNvdXN0aWNzX21pciA8LSBhY291c3RpY3NfbWlyICU+JQogIGxlZnRfam9pbihhdWRpb19kZXNjcmlwdGl2ZXMgJT4lCiAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChhdWRpb19uYW1lLCBsYWJlbCwgbWVhbl9tb25yYSksCiAgICAgICAgICAgIGJ5ID0gImF1ZGlvX25hbWUiKSAlPiUKICBkcGx5cjo6c2VsZWN0KGF1ZGlvX25hbWUsIGxhYmVsLCBtZWFuX21vbnJhLCBldmVyeXRoaW5nKCkpCgoKYWNvdXN0aWNzX21pciA8LSBhY291c3RpY3NfbWlyICU+JQogIGRwbHlyOjpzZWxlY3QoIWlkKSAlPiUKICBkcGx5cjo6c2VsZWN0KCFhdmVyYWdlX2xvdWRuZXNzLnZhbHVlKSAKCmFjb3VzdGljc19taXIgPC0gYWNvdXN0aWNzX21pciAlPiUgZHBseXI6OnNlbGVjdCgsIDE6MjUxKQoKbmFtZXMoYWNvdXN0aWNzX21pcikKCmBgYAoKClNjYWxlIGRhdGE6CmBgYHtyfQoKc2NhbGVkX21pcl8gPC0gYWNvdXN0aWNzX21pciB8PiAKICBzZWxlY3QoIW1lYW5fbW9ucmEpIHw+IAogIG11dGF0ZV9pZihpcy5udW1lcmljLHNjYWxlKQoKIyBTY2FsZSBjb2x1bW5zIDQgdG8gMjUxCnNjYWxlZF9jb2x1bW5zIDwtIHNjYWxlKGFjb3VzdGljc19taXJbLCA0OjI1MV0pCgojIENvbWJpbmUgdGhlIHVuc2NhbGVkIGZpcnN0IHRocmVlIGNvbHVtbnMgd2l0aCB0aGUgc2NhbGVkIGNvbHVtbnMKYWNvdXN0aWNzX21pcl9zY2FsZWQgPC0gY2JpbmQoYWNvdXN0aWNzX21pclssIDE6M10sIGFzLmRhdGEuZnJhbWUoc2NhbGVkX2NvbHVtbnMpKQoKI3Jvd25hbWVzKG51bWVyaWNfbWlyKSA8LSBzY2FsZWRfbWlyX1ssMV0KCnN0cihudW1lcmljX21pcikKbmFtZXMoc2NhbGVkX21pcl8pCm5hbWVzKGFjb3VzdGljc19taXIpCgpgYGAKCkZpcnN0IGNsZWFuIG91dCBvYnZpb3VzbHkgcmVkdW5kYW50IGZlYXR1cmVzLiAKYmFya2JhbmRzLmRtZWFuXzAxLTI3IGFyZSB0aGUgc2FtZSBhcyBmcmVxdWVuY3lfYmFuZHMuZG1lYW5fMDEtMjc7IHN1YmJhbmRfbWVhbi9zdGQgKDItMTApIHNhbWUgYXMgbWZjYzJfbWVhbi9zdGQ7IGFsc28gcmVtb3ZlIHNwZWN0cmFsX2VuZXJneWJhbmRfbG93LmR2YXIKClRoZXNlIGFyZSA3MiBhY291c3RpYyBmZWF0dXJlcyB0aGF0IGRvIG5vdCBoYXZlIGNvcnJlbGF0aW9ucyBhYm92ZSAuNzUgd2l0aCBlYWNoIG90aGVyLgoKYGBge3J9CmhpZ2hseV9jb3JyPC1mdXp6eVNpbTo6Y29yU2VsZWN0KGFjb3VzdGljc19taXJfc2NhbGVkWywgNDoyNTFdLCBjb3IudGhyZXNoID0gLjc1LCB2YXIuY29scyA9MToyNDgpCgpyZWR1bmRhbnRfdmFyaWFibGVzPC1oaWdobHlfY29yciRleGNsdWRlZC52YXJzWzE6MTc2XQoKY291bnQoaGlnaGx5X2NvcnIkaGlnaC5jb3JyZWxhdGlvbnMpCgpudW1lcmljX21pcl9leGNsdWRlZCA8LSBudW1lcmljX21pciAlPiUgZHBseXI6OnNlbGVjdCghYWxsX29mKHJlZHVuZGFudF92YXJpYWJsZXMpKSAKCmFjb3VzdGljc19taXJfc2NhbGVkX25vY29sbGluZWFyIDwtIGFjb3VzdGljc19taXJfc2NhbGVkICU+JSBkcGx5cjo6c2VsZWN0KCFhbGxfb2YocmVkdW5kYW50X3ZhcmlhYmxlcykpIAoKCm5hbWVzKG51bWVyaWNfbWlyKQpgYGAKCgpOb3csIHdlIGNvcnJlbGF0ZSBlYWNoIGFjb3VzdGljIGZlYXR1cmUgd2l0aCBtZWFuIG11c2ljIHJhdGluZ3MgdG8gc2VlIGhvdyB0aGUgcmVsYXRpb25zaGlwcyBsb29rIGxpa2UKYGBge3J9CgphY291c3RpY19mZWF0dXJlc190b19jb3JyZWxhdGUgPC0gYWNvdXN0aWNzX21pcl9zY2FsZWRfbm9jb2xsaW5lYXJbLCAKICAgICAgICAgICAgICAgIHNhcHBseShhY291c3RpY3NfbWlyX3NjYWxlZF9ub2NvbGxpbmVhciwgaXMubnVtZXJpYykgJiAKICAgICAgICAgICAgICAgIG5hbWVzKGFjb3VzdGljc19taXJfc2NhbGVkX25vY29sbGluZWFyKSAhPSAibWVhbl9tb25yYSIKICAgICAgICAgICAgICBdCgojIENvbXB1dGUgY29ycmVsYXRpb25zCmZ1bGxfY29yX3Jlc3VsdHMgPC0gc2FwcGx5KGFjb3VzdGljX2ZlYXR1cmVzX3RvX2NvcnJlbGF0ZSwgZnVuY3Rpb24oY29sdW1uKSB7CiAgY29yKGNvbHVtbiwgYWNvdXN0aWNzX21pcl9zY2FsZWRfbm9jb2xsaW5lYXIkbWVhbl9tb25yYSwgdXNlID0gImNvbXBsZXRlLm9icyIpCn0pCgojIEZvcm1hdCByZXN1bHRzCmZ1bGxfY29yX2RmIDwtIGRhdGEuZnJhbWUoCiAgVmFyaWFibGUgPSBuYW1lcyhmdWxsX2Nvcl9yZXN1bHRzKSwKICBDb3JyZWxhdGlvbiA9IGZ1bGxfY29yX3Jlc3VsdHMsCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKCiMgT3JkZXIgYnkgYWJzb2x1dGUgY29ycmVsYXRpb24KZnVsbF9jb3JfZGYgPC0gZnVsbF9jb3JfZGZbb3JkZXIoLWFicyhmdWxsX2Nvcl9kZiRDb3JyZWxhdGlvbikpLCBdCgojIFNob3cgcmVzdWx0CnByaW50KGZ1bGxfY29yX2RmKQoKYGBgCgoKTm93LCBzZWxlY3QgdGhlIDEwIGFjb3VzdGljIGZlYXR1cmVzIHRoYXQgaGF2ZSB0aGUgYWJvbHN1dGUgaGlnaGVzdCBjb3JyZWxhdGlvbiB0byBtZWFuX21vbnJhCmBgYHtyfQphY291c3RpY3NfY2x1c3Rlcl9hYnNvbHV0ZV9jb3JyIDwtIGRwbHlyOjpzZWxlY3QoYWNvdXN0aWNzX21pcl9zY2FsZWRfbm9jb2xsaW5lYXIsIGF1ZGlvX25hbWUsIGxhYmVsLCBtZWFuX21vbnJhLCBwaXRjaF9zYWxpZW5jZS5kbWVhbiwgc2lsZW5jZV9yYXRlXzMwZEIuZG1lYW4sIHNjdmFsbGV5cy5kdmFyXzAxLCBnZmNjLmRtZWFuXzExLCBnZmNjLmRtZWFuXzA5LCB6ZXJvY3Jvc3NpbmdyYXRlLmR2YXIsIHBpdGNoX2luc3RhbnRhbmVvdXNfY29uZmlkZW5jZS5kdmFyLCBzcGVjdHJhbF9jb250cmFzdC5kdmFyXzAxLCBiYXJrYmFuZHMuZG1lYW5fMjMsIGdmY2MuZG1lYW5fMTMpCgp3cml0ZV94bHN4KGFjb3VzdGljc19jbHVzdGVyX2Fic29sdXRlX2NvcnIsICJhY291c3RpY3NfY2x1c3Rlcl9hYnNvbHV0ZV9jb3JyLnhsc3giKQoKCndyaXRlX3hsc3goYWNvdXN0aWNzX21pcl9zY2FsZWRfbm9jb2xsaW5lYXIsICJhY291c3RpY3NfbWlyX3NjYWxlZF9ub2NvbGxpbmVhci54bHN4IikKYGBgCgoKQ29tcGFyaW5nIGFjb3VzdGljIHZzLiBwZXJjZXB0dWFsIGZlYXR1cmVzIGluIHByZWRpY3RpbmcgYSBtdXNpYyBjYXRlZ29yeQoKClBhY2thZ2VzCgpgYGB7cn0KCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGJyb29tLm1peGVkKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGNvd3Bsb3QpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZmFjdG9leHRyYSkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShnZ2ZvcnRpZnkpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkobG1lNCkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShsbWVyVGVzdCkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShvcmRpbmFsKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHJjb21wYW5pb24pKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoc3RhdHMpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkod3JpdGV4bCkpKQoKYGBgCgpSZWFkaW5nIGluIERGcwoKYGBge3J9CmFjb3VzdGljc19taXJfc2NhbGVkX25vY29sbGluZWFyIDwtIHJlYWRfZXhjZWwoImFjb3VzdGljc19taXJfc2NhbGVkX25vY29sbGluZWFyLnhsc3giLAogICAgc2hlZXQgPSAiU2hlZXQxIikgCgphdWRpb19kZXNjcmlwdGl2ZXMgPC0gcmVhZF9leGNlbCgiYXVkaW9fZmVhdHVyZXMueGxzeCIsCiAgICBzaGVldCA9ICJTaGVldDEiKSAKCm1vbnJhX2RhdGEgPC0gcmVhZF9leGNlbCgibW9ucmFfZGF0YS54bHN4IiwKICAgIHNoZWV0ID0gIlNoZWV0MSIpIAoKYWNvdXN0aWNzX2NsdXN0ZXJfYWJzb2x1dGVfY29yciA8LSByZWFkX2V4Y2VsKCJhY291c3RpY3NfY2x1c3Rlcl9hYnNvbHV0ZV9jb3JyLnhsc3giLAogICAgc2hlZXQgPSAiU2hlZXQxIikgCgpgYGAKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBQQ0EgV0lUSCBQRVJDRVBUVUFMIEZFQVRVUkVTCgpXZSByZWR1Y2UgdGhlIGRpbWVuc2lvbmFsaXR5IG9mIG91ciBwZXJjZXB0dWFsIGZlYXR1cmVzIHRvIGxhdGVyIHVzZSB0aGVzZSBwcmluY2lwYWwgY29tcG9uZW50cyBpbiBtb2RlbGluZy4gV2Ugc2VsZWN0IHRoZSBmaXJzdCB0d28gcHJpbmNpcGFsIGNvbXBvbmVudHMgaGVyZS4gCgpgYGB7cn0KCnBjYV9yZXN1bHRfcGVyY2VwdHVhbCA8LSBwcmNvbXAoYXVkaW9fZGVzY3JpcHRpdmVzWywzOjEyXSwgY2VudGVyID0gVFJVRSwgc2NhbGUuID0gVFJVRSkKCgpmdml6X2VpZyhwY2FfcmVzdWx0X3BlcmNlcHR1YWwsIGFkZGxhYmVscyA9IFRSVUUpCgplaWcudmFsX3BlciA8LSBnZXRfZWlnZW52YWx1ZShwY2FfcmVzdWx0X3BlcmNlcHR1YWwpCmVpZy52YWxfcGVyCgojIG51bWJlciBvZiBQQ3MgdG8ga2VlcApwY2RpbXNfcGVyID0gMTAKCiMgUHJpbnQgZWlnZW52YWx1ZXMKZWlnLnZhbF9wZXJbYygxOnBjZGltc19wZXIpLF0KCnJlcy5mZWF0c19wZXIgPC0gZ2V0X3BjYV92YXIocGNhX3Jlc3VsdF9wZXJjZXB0dWFsKQoKY29udHJpYmRmX3BlciAgPSBhcy5kYXRhLmZyYW1lKHJlcy5mZWF0c19wZXIkY29udHJpYlssYygxOnBjZGltc19wZXIpXSkKcm91bmQoY29udHJpYmRmX3BlciwgZGlnaXRzPTIpCgpsb2FkaW5nc19wZXIgPC0gcGNhX3Jlc3VsdF9wZXJjZXB0dWFsJHJvdGF0aW9uCmxvYWRpbmdzX3BlclssYygxOjIpXQoKcmVzLmluZF9wZXIgPC0gZ2V0X3BjYV9pbmQocGNhX3Jlc3VsdF9wZXJjZXB0dWFsKQoKcGNfc2NvcmVzX3BlciA9IHBjYV9yZXN1bHRfcGVyY2VwdHVhbCR4CgpwY2FfZGF0YV9wZXJjIDwtIGFzLmRhdGEuZnJhbWUocGNhX3Jlc3VsdF9wZXJjZXB0dWFsJHgpCnBjYV9kYXRhX3BlcmMkbGFiZWwgPC0gbWlyX21vbnJhMiRsYWJlbAoKYXVkaW9fZGVzY3JpcHRpdmVzJFBDMSA9IHBjX3Njb3Jlc19wZXJbLDFdKi0xCmF1ZGlvX2Rlc2NyaXB0aXZlcyRQQzIgPSBwY19zY29yZXNfcGVyWywyXQoKIyBOb3cgcmUtcnVuIHRoZSBwbG90dGluZwpmdml6X3BjYV9iaXBsb3QocGNhX3Jlc3VsdF9wZXJjZXB0dWFsLAogICAgICAgICAgICAgICAgbGFiZWwgPSAidmFyIiwgICAgICAgICMgb25seSB2YXJpYWJsZSBuYW1lcwogICAgICAgICAgICAgICAgaGFiaWxsYWdlID0gbWlyX21vbnJhMiRsYWJlbCwKICAgICAgICAgICAgICAgIGFkZEVsbGlwc2VzID0gVFJVRSwKICAgICAgICAgICAgICAgIGNvbC52YXIgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgcmVwZWwgPSBUUlVFKQoKZnZpel9laWcocGNhX3Jlc3VsdF9wZXJjZXB0dWFsLCBhZGRsYWJlbHMgPSBUUlVFLCB5bGltID0gYygwLCAxMDApKSArCiAgdGhlbWVfbWluaW1hbCgpICsgICMgTWluaW1hbCB0aGVtZSBmb3IgYSBjbGVhbiBsb29rCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAgICAjIFJlbW92ZSBtYWpvciBncmlkIGxpbmVzCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAgICAjIFJlbW92ZSBtaW5vciBncmlkIGxpbmVzCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAgICAjIFJlbW92ZSBiYWNrZ3JvdW5kIGNvbG9yCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksICAjIEFkZCBheGlzIGxpbmVzCiAgICBsZWdlbmQucG9zaXRpb24gPSAiTk9ORSIsICAgICAgICAgICAgICMgUmVtb3ZlIHRoZSBsZWdlbmQKICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkgCgoKYGBgCgpQQ0EgdG8gcmVkdWNlIHRoZSBudW1iZXIgb2YgYWNvdXN0aWMgZmVhdHVyZXMsIHdlIHNlbGVjdCB0aGUgZmlyc3QgMiBwcmluY2lwYWwgY29tcG9uZW50cy4gCgpgYGB7cn0KYWNvdXN0aWNzX2NsdXN0ZXJfYWJzb2x1dGVfY29yciA8LSBhY291c3RpY3NfY2x1c3Rlcl9hYnNvbHV0ZV9jb3JyICU+JQogIG11dGF0ZShvcmRlciA9IGlmZWxzZShsYWJlbCA9PSAibm9uLW11c2ljIiwgMSwKICAgICAgICAgICAgICAgICBpZmVsc2UobGFiZWwgPT0gImFtYmlndW91cyIsIDIsCiAgICAgICAgICAgICAgICAgaWZlbHNlKGxhYmVsID09ICJtdXNpYyIsIDMsIE5BKSkpKQoKYWNvdXN0aWNzX2NsdXN0ZXJfYWJzb2x1dGVfY29yciRvcmRlciA8LSBhcy5mYWN0b3IoYWNvdXN0aWNzX2NsdXN0ZXJfYWJzb2x1dGVfY29yciRvcmRlcikKCgpwY2FfcmVzdWx0X2FicyA8LSBwcmNvbXAoYWNvdXN0aWNzX2NsdXN0ZXJfYWJzb2x1dGVfY29ycls0OjEzXSwgY2VudGVyID0gVFJVRSwgc2NhbGUuID0gRkFMU0UpCgpmdml6X2VpZyhwY2FfcmVzdWx0X2FicywgYWRkbGFiZWxzID0gVFJVRSwgeWxpbSA9IGMoMCwgMTAwKSkgKwogIHRoZW1lX21pbmltYWwoKSArICAjIE1pbmltYWwgdGhlbWUgZm9yIGEgY2xlYW4gbG9vawogIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICAgIyBSZW1vdmUgbWFqb3IgZ3JpZCBsaW5lcwogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgICAgIyBSZW1vdmUgbWlub3IgZ3JpZCBsaW5lcwogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgICAgIyBSZW1vdmUgYmFja2dyb3VuZCBjb2xvcgogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpLCAgIyBBZGQgYXhpcyBsaW5lcwogICAgbGVnZW5kLnBvc2l0aW9uID0gIk5PTkUiLCAgICAgICAgICAgICAjIFJlbW92ZSB0aGUgbGVnZW5kCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpIAoKIyBQbG90IHRoZSBmaXJzdCAyIHByaW5jaXBhbCBjb21wb25lbnRzCmF1dG9wbG90KHBjYV9yZXN1bHRfYWJzLCAKICAgICAgICAgZGF0YSA9IGFjb3VzdGljc19jbHVzdGVyX2Fic29sdXRlX2NvcnIsCiAgICAgICAgIHggPSAxLAogICAgICAgICB5ID0gMiwKICAgICAgICAgY29sb3VyID0gJ2xhYmVsJywgCiAgICAgICAgIGxvYWRpbmdzID0gVFJVRSwgCiAgICAgICAgIGxvYWRpbmdzLmxhYmVsID0gVFJVRSwKICAgICAgICAgbG9hZGluZ3MuY29sb3IgPSAiYmxhY2siLAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5jb2xvciA9ICJibGFjayIsCiAgICAgICAgIGxvYWRpbmdzLmxhYmVsLnJlcGVsID0gVFJVRSwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuc2l6ZSA9IDUsCiAgICAgICAgIGZyYW1lID0gVFJVRSwKICAgICAgICAgZnJhbWUudHlwZSA9ICdub3JtJykgKwogICMgQ3VzdG9taXplIGFwcGVhcmFuY2UKICB0aGVtZV9taW5pbWFsKCkgKyAgCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAgICAKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksICAgIAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgICAgCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksICAKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJOT05FIiwgICAgICAgICAgICAgCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCkgICAgICAgICAKICApICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJtdXNpYyIgPSAicmVkIiwgImFtYmlndW91cyIgPSAiYmx1ZSIsICJub24tbXVzaWMiID0gImdyZWVuIikpICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibXVzaWMiID0gInJlZCIsICJhbWJpZ3VvdXMiID0gImJsdWUiLCAibm9uLW11c2ljIiA9ICJncmVlbiIpKSArIAogIGxhYnMoCiAgICB0aXRsZSA9ICIgIiwKICAgIGNvbG91ciA9ICJNZWFuIE1PTlJBIFJhdGluZyIKICApICsKICBzY2FsZV95X3JldmVyc2UoKSAKCgpwY19zY29yZWFicyA9IHBjYV9yZXN1bHRfYWJzJHgKCmFjb3VzdGljc19jbHVzdGVyX2Fic29sdXRlX2NvcnIkUEMxYWMgPSBwY19zY29yZWFic1ssMV0KYWNvdXN0aWNzX2NsdXN0ZXJfYWJzb2x1dGVfY29yciRQQzJhYyA9IHBjX3Njb3JlYWJzWywyXQpgYGAKCkhlcmUsIHdlIGNhcnJ5IG91dCAyIGN1bXVsYXRpdmUgbGluayBtb2RlbHMgdG8gcHJlZGljdCBjYXRlZ29yaWVzIHVzaW5nIHRoZSBvcmRpbmFsIHBhY2thZ2UgaW4gMiBzZXBhcmF0ZSBtb2RlbHM6IGFjb3VzdGljIG1vZGVsIGFuZCB0aGUgcGVyY2VwdHVhbCBtb2RlbAoKYGBge3J9CgpjbG1fZGYgPC0gYXVkaW9fZGVzY3JpcHRpdmVzIHw+IAogIGRwbHlyOjpzZWxlY3QoYXVkaW9fbmFtZSwgUEMxLCBQQzIpIHw+IApsZWZ0X2pvaW4oYWNvdXN0aWNzX2NsdXN0ZXJfYWJzb2x1dGVfY29yciB8PiAKICAgICAgICAgICAgZHBseXI6OnNlbGVjdChhdWRpb19uYW1lLCBQQzFhYywgUEMyYWMpLAogICAgICAgICAgYnkgPSAiYXVkaW9fbmFtZSIpIHw+IApsZWZ0X2pvaW4ocmF0aW5nc19vcmRlciB8PiAKICAgICAgICAgICAgZGlzdGluY3QoYXVkaW9fbmFtZSwgb3JkZXIpLCAKICAgICAgICAgIGJ5ID0gImF1ZGlvX25hbWUiKQoKY2xtX2FjX2FicyA8LSBjbG0ob3JkZXIgfiBQQzFhYyArIFBDMmFjLCBkYXRhID0gY2xtX2RmKQpjbG1fcGVyY2VwdHVhbCA8LSBjbG0ob3JkZXIgfiBQQzEgKyBQQzIsIGRhdGEgPSBjbG1fZGYpCmNsbV9vcmRlcl9udWxsIDwtIGNsbShvcmRlciB+IDEsIGRhdGEgPSBjbG1fZGYpCgpzdW1tYXJ5KGNsbV9hY19hYnMpCnN1bW1hcnkoY2xtX3BlcmNlcHR1YWwpCgphbm92YShjbG1fYWNfYWJzLCBjbG1fb3JkZXJfbnVsbCkKYW5vdmEoY2xtX3BlcmNlcHR1YWwsIGNsbV9vcmRlcl9udWxsKQoKcFIyKGxtX29yZGVyX2FjKQoKIyMjUHNldWRvIHIgc3FhdXJlZApuYWdlbGtlcmtlKGNsbV9hY19hYnMsIGNsbV9vcmRlcl9udWxsKQpuYWdlbGtlcmtlKGNsbV9wZXJjZXB0dWFsLCBjbG1fb3JkZXJfbnVsbCkKCiMgQ29tcGFyZSBBSUMKQUlDKGNsbV9wZXJjZXB0dWFsLCBjbG1fYWNfYWJzKQoKIyBDb21wYXJlIEJJQwpCSUMoY2xtX3BlcmNlcHR1YWwsIGNsbV9hY19hYnMpCgoKd3JpdGVfeGxzeChjbG1fZGYsICJjbG1fZGYueGxzeCIpCmBgYAoKSGVuY2UsIHRoZSBwZXJjZXB0dWFsIG1vZGVsIG91dHBlcmZvcm1zIHRoZSBhY291dGljIG1vZGVsLiAKClJlcG9ydGVkIFBDQSBQbG90cyAoRmlndXJlIDNBKQoKYGBge3J9CmxpYnJhcnkoY293cGxvdCkKCmFjb3VzdGljX3BjYV9wbG90IDwtIGF1dG9wbG90KHBjYV9yZXN1bHRfYWJzLCAKICAgICAgICAgZGF0YSA9IGFjb3VzdGljc19jbHVzdGVyX2Fic29sdXRlX2NvcnIsIAogICAgICAgICBjb2xvdXIgPSAnbGFiZWwnLCAKICAgICAgICAgbG9hZGluZ3MgPSBUUlVFLCAKICAgICAgICAgbG9hZGluZ3MubGFiZWwgPSBUUlVFLAogICAgICAgICBsb2FkaW5ncy5jb2xvciA9ICJibGFjayIsCiAgICAgICAgIGxvYWRpbmdzLmxhYmVsLmNvbG9yID0gImJsYWNrIiwKICAgICAgICAgbG9hZGluZ3MubGFiZWwucmVwZWwgPSBUUlVFLAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5zaXplID0gNSwKICAgICAgICAgZnJhbWUgPSBUUlVFLAogICAgICAgICBmcmFtZS50eXBlID0gJ25vcm0nKSArCiAgIyBDdXN0b21pemUgYXBwZWFyYW5jZQogIHRoZW1lX21pbmltYWwoKSArICAjIE1pbmltYWwgdGhlbWUgZm9yIGEgY2xlYW4gbG9vawogIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICAgIyBSZW1vdmUgbWFqb3IgZ3JpZCBsaW5lcwogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgICAgIyBSZW1vdmUgbWlub3IgZ3JpZCBsaW5lcwogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgICAgIyBSZW1vdmUgYmFja2dyb3VuZCBjb2xvcgogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpLCAgIyBBZGQgYXhpcyBsaW5lcwogICAgbGVnZW5kLnBvc2l0aW9uID0gIk5PTkUiLCAgICAgICAgICAgICAjIFJlbW92ZSB0aGUgbGVnZW5kCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCkgICAgICAgICAjIEluY3JlYXNlIHRleHQgc2l6ZQogICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJtdXNpYyIgPSAicmVkIiwgImFtYmlndW91cyIgPSAiYmx1ZSIsICJub24tbXVzaWMiID0gImdyZWVuIikpICsKICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygibXVzaWMiID0gInJlZCIsICJhbWJpZ3VvdXMiID0gImJsdWUiLCAibm9uLW11c2ljIiA9ICJncmVlbiIpKSArICMgQ3VzdG9tIGNvbG9ycwogIGxhYnMoCiAgICB0aXRsZSA9ICIgIiwKICAgIGNvbG91ciA9ICJNZWFuIE1PTlJBIFJhdGluZyIgICAgICAgICAgICMgTGFiZWwgZm9yIHRoZSBsZWdlbmQKICApIAoKcGVyY2VwdHVhbF9wY2FfcGxvdCA8LSBhdXRvcGxvdChwY2FfcmVzdWx0X3BlcmNlcHR1YWwsIAogICAgICAgICBkYXRhID0gYXVkaW9fZGVzY3JpcHRpdmVzLCAKICAgICAgICAgY29sb3VyID0gJ2xhYmVsJywgCiAgICAgICAgIGxvYWRpbmdzID0gVFJVRSwgCiAgICAgICAgIGxvYWRpbmdzLmxhYmVsID0gVFJVRSwKICAgICAgICAgbG9hZGluZ3MuY29sb3IgPSAiYmxhY2siLAogICAgICAgICBsb2FkaW5ncy5sYWJlbC5jb2xvciA9ICJibGFjayIsCiAgICAgICAgIGxvYWRpbmdzLmxhYmVsLnJlcGVsID0gVFJVRSwKICAgICAgICAgbG9hZGluZ3MubGFiZWwuc2l6ZSA9IDUsCiAgICAgICAgIGZyYW1lID0gVFJVRSwKICAgICAgICAgZnJhbWUudHlwZSA9ICdub3JtJykgKwogICMgQ3VzdG9taXplIGFwcGVhcmFuY2UKICB0aGVtZV9taW5pbWFsKCkgKyAgIyBNaW5pbWFsIHRoZW1lIGZvciBhIGNsZWFuIGxvb2sKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksICAgICMgUmVtb3ZlIG1ham9yIGdyaWQgbGluZXMKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksICAgICMgUmVtb3ZlIG1pbm9yIGdyaWQgbGluZXMKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksICAgICMgUmVtb3ZlIGJhY2tncm91bmQgY29sb3IKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSwgICMgQWRkIGF4aXMgbGluZXMKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJOT05FIiwgICAgICAgICAgICAgIyBSZW1vdmUgdGhlIGxlZ2VuZAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApICAgICAgICAgIyBJbmNyZWFzZSB0ZXh0IHNpemUKICApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygibXVzaWMiID0gInJlZCIsICJhbWJpZ3VvdXMiID0gImJsdWUiLCAibm9uLW11c2ljIiA9ICJncmVlbiIpKSArCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIm11c2ljIiA9ICJyZWQiLCAiYW1iaWd1b3VzIiA9ICJibHVlIiwgIm5vbi1tdXNpYyIgPSAiZ3JlZW4iKSkgKyAjIEN1c3RvbSBjb2xvcnMKICBsYWJzKAogICAgdGl0bGUgPSAiICIsCiAgICBjb2xvdXIgPSAiTWVhbiBNT05SQSBSYXRpbmciICAgICAgICAgICAjIExhYmVsIGZvciB0aGUgbGVnZW5kCiAgKSAKCmxlZ2VuZF9wY2EgPC0gZ2dwbG90KGRhdGEgPSBhdWRpb19kZXNjcmlwdGl2ZXMsIGFlcyh4ID0gMSwgeSA9IDEsIGNvbG91ciA9IGxhYmVsKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIm11c2ljIiA9ICJyZWQiLCAiYW1iaWd1b3VzIiA9ICJibHVlIiwgIm5vbi1tdXNpYyIgPSAiZ3JlZW4iKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQW1iaWd1b3VzIiwgIk11c2ljIiwgIk5vbi1tdXNpYyIpKSArCiAgdGhlbWVfdm9pZCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNSkpKSArCiAgbGFicyhjb2xvdXIgPSBOVUxMKSAgIyBSZW1vdmUgdGhlIGxlZ2VuZCB0aXRsZQoKCmxvYWRpbmdzX2xhYmVscyA8LSByb3duYW1lcyhwY2FfcmVzdWx0X3BlcmNlcHR1YWwkcm90YXRpb24pCgojIFJlbW92ZSAibWVhbl8iIGZyb20gdGhlIGxvYWRpbmdzIGxhYmVscyBhbmQgY2FwaXRhbGl6ZSB0aGUgZmlyc3QgbGV0dGVyCmxvYWRpbmdzX2xhYmVscyA8LSBnc3ViKCJebWVhbl8iLCAiIiwgbG9hZGluZ3NfbGFiZWxzKSAgIyBSZW1vdmUgIm1lYW5fIgpsb2FkaW5nc19sYWJlbHMgPC0gdG9vbHM6OnRvVGl0bGVDYXNlKGxvYWRpbmdzX2xhYmVscykgICMgQ2FwaXRhbGl6ZSBmaXJzdCBsZXR0ZXIKCiMgUmVhc3NpZ24gdGhlIG1vZGlmaWVkIGxhYmVscyBiYWNrIHRvIHRoZSBQQ0Egb2JqZWN0CnJvd25hbWVzKHBjYV9yZXN1bHRfcGVyY2VwdHVhbCRyb3RhdGlvbikgPC0gbG9hZGluZ3NfbGFiZWxzCgoKCmNvd3Bsb3Q6OnBsb3RfZ3JpZChhY291c3RpY19wY2FfcGxvdCwgcGVyY2VwdHVhbF9wY2FfcGxvdCwgbGVnZW5kX3BjYSwgbmNvbCA9IDMsIHJlbF93aWR0aHMgPSBjKDAuOCwgMC44LCAwLjEpKQoKCmBgYAoKQm94cGxvdHMgb2YgbWVhbiBmZWF0dXJlIHJhdGluZ3MgYWNyb3NzIGNsdXN0ZXJzIChGaWd1cmUgM0IpCmBgYHtyfQoKYXVkaW9fZmVhdHVyZXNfbG9uZyA8LSBwaXZvdF9sb25nZXIoYXVkaW9fZmVhdHVyZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xzID0gYyhtZWFuX3B1bHNlLCBtZWFuX3JoeXRobSwgbWVhbl9yZXBldGl0aW9uLCBtZWFuX21lbG9keSwgbWVhbl9pbnN0cnVtZW50YWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbl90aW1icmUsIG1lYW5fdGVtcG8sIG1lYW5faW50ZW50aW9uYWxpdHksIG1lYW5faGFybW9ueSwgbWVhbl9jb21wbGV4aXR5KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJ2YXJpYWJsZSIsICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlIikKCmF1ZGlvX2ZlYXR1cmVzX2xvbmckdmFyaWFibGUgPC0gYXMuZmFjdG9yKGF1ZGlvX2ZlYXR1cmVzX2xvbmckdmFyaWFibGUpCmF1ZGlvX2ZlYXR1cmVzX2xvbmckbGFiZWwgPC0gZmFjdG9yKGF1ZGlvX2ZlYXR1cmVzX2xvbmckbGFiZWwsIGxldmVscyA9IGMoIm11c2ljIiwgImFtYmlndW91cyIsICJub24tbXVzaWMiKSkKCgogIyBNb2RpZnkgdGhlICd2YXJpYWJsZScgY29sdW1uOiBSZW1vdmUgIm1lYW5fIiBhbmQgY2FwaXRhbGl6ZSB0aGUgZmlyc3QgbGV0dGVyCmF1ZGlvX2ZlYXR1cmVzX2xvbmcgPC0gYXVkaW9fZmVhdHVyZXNfbG9uZyAlPiUKICBtdXRhdGUodmFyaWFibGUgPSBnc3ViKCJebWVhbl8iLCAiIiwgdmFyaWFibGUpLCAgICAgICMgUmVtb3ZlICJtZWFuXyIKICAgICAgICAgdmFyaWFibGUgPSB0b29sczo6dG9UaXRsZUNhc2UodmFyaWFibGUpKSAgICAgIyBDYXBpdGFsaXplIGZpcnN0IGxldHRlcgoKYXVkaW9fZmVhdHVyZXNfbG9uZyR2YXJpYWJsZSA8LSBmYWN0b3IoYXVkaW9fZmVhdHVyZXNfbG9uZyR2YXJpYWJsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiSW50ZW50aW9uYWxpdHkiLCAiSW5zdHJ1bWVudGFsIiwgIkNvbXBsZXhpdHkiLCAiUmVwZXRpdGlvbiIsICJNZWxvZHkiLCAiSGFybW9ueSIsICJSaHl0aG0iLCAiVGVtcG8iLCAiVGltYnJlIiwgIlB1bHNlIikpCgoKIHJhdGluZ3NfY2x1c3Rlcl9wbG90X21lYW4gPC0gZ2dwbG90KGF1ZGlvX2ZlYXR1cmVzX2xvbmcsIGFlcyh4ID0gbGFiZWwsIHkgPSB2YWx1ZSwgY29sb3IgPSBsYWJlbCwgZmlsbCA9IGxhYmVsKSkgKwogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzUpKSArCiAgIGdlb21faml0dGVyKGFscGhhID0gMC4zLCBzaXplID0gMSkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTYpICsgICMgSW5jcmVhc2UgYmFzZSBmb250IHNpemUKICB0aGVtZSgKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYWNlID0gImJvbGQiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgICMgSGlkZSBsZWdlbmQKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwgICMgRmFjZXQgbGFiZWwgdGV4dAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICMgUmVtb3ZlIG1ham9yIGdyaWQgbGluZXMKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSksICMgUm90YXRlIHgtYXhpcyB0ZXh0CiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwKQogICkgKwogICB5bGltKDAsMTAwKSArCiAgbGFicygKICAgIHRpdGxlID0gIiAiLAogICAgeCA9ICIgIiwKICAgIHkgPSAiUmF0aW5ncyIKICApICsKICBmYWNldF9ncmlkKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWVfeCIsIHNwYWNlID0gImZyZWUiKSAgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJtdXNpYyIgPSAicmVkIiwgImFtYmlndW91cyIgPSAiYmx1ZSIsICJub24tbXVzaWMiID0gIiMzQ0IzNzEiKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIm11c2ljIiA9ICJyZWQiLCAiYW1iaWd1b3VzIiA9ICJibHVlIiwgIm5vbi1tdXNpYyIgPSAiIzNDQjM3MSIpKQoKIApyYXRpbmdzX2NsdXN0ZXJfcGxvdF9tZWFuCgpgYGAKCgpSYWRhciBDaGFydCBvZiBtZWFuIGZlYXR1cmUgcmF0aW5ncyBmb3IgZGlmZmVyZW50IGNsdXN0ZXJzIChGaWd1cmUgM0MpCmBgYHtyfQoKYXVkaW9fZGVzY3JpcHRpdmVzX3dvX21vbnJhIDwtIGF1ZGlvX2Rlc2NyaXB0aXZlcyAlPiUKICBkcGx5cjo6c2VsZWN0KGNsdXN0ZXIsbGFiZWwsIG1lYW5fcmVwZXRpdGlvbiwgbWVhbl90aW1icmUsIG1lYW5fdGVtcG8sIG1lYW5fcHVsc2UsIG1lYW5faGFybW9ueSwgbWVhbl9tZWxvZHksIG1lYW5fcmh5dGhtLCBtZWFuX2NvbXBsZXhpdHksIG1lYW5faW50ZW50aW9uYWxpdHksIG1lYW5faW5zdHJ1bWVudGFsKQoKc3ViZ3JvdXBfc3VtbWFyeV9wYWcgPC0gYXVkaW9fZGVzY3JpcHRpdmVzX3dvX21vbnJhICU+JQogIGdyb3VwX2J5KGxhYmVsKSAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKHN0YXJ0c193aXRoKCJtZWFuIiksIGxpc3QobWVhbiA9IG1lYW4pLCAubmFtZXMgPSAiey5jb2x9X3suZm59IikpICU+JQogIHJlbmFtZShtZWFuX3B1bHNlID0gbWVhbl9wdWxzZV9tZWFuLAogICAgICAgICBtZWFuX3JoeXRobSA9IG1lYW5fcmh5dGhtX21lYW4sCiAgICAgICAgIG1lYW5fdGltYnJlID0gbWVhbl90aW1icmVfbWVhbiwKICAgICAgICAgbWVhbl9yZXBldGl0aW9uID0gbWVhbl9yZXBldGl0aW9uX21lYW4sCiAgICAgICAgIG1lYW5fdGVtcG8gPSBtZWFuX3RlbXBvX21lYW4sCiAgICAgICAgIG1lYW5fbWVsb2R5ID0gbWVhbl9tZWxvZHlfbWVhbiwKICAgICAgICAgbWVhbl9oYXJtb255ID0gbWVhbl9oYXJtb255X21lYW4sCiAgICAgICAgIG1lYW5faW50ZW50aW9uYWxpdHkgPSBtZWFuX2ludGVudGlvbmFsaXR5X21lYW4sCiAgICAgICAgIG1lYW5faW5zdHJ1bWVudGFsID0gbWVhbl9pbnN0cnVtZW50YWxfbWVhbiwKICAgICAgICAgbWVhbl9jb21wbGV4aXR5ID0gbWVhbl9jb21wbGV4aXR5X21lYW4pIAoKCiMgUHJlcGFyZSB0aGUgZGF0YSBieSBhZGRpbmcgbWF4IGFuZCBtaW4gcm93cwptYXhfdmFsdWVzIDwtIHJlcCgxMDAsIG5jb2woc3ViZ3JvdXBfc3VtbWFyeV9wYWcpIC0gMSkKbWluX3ZhbHVlcyA8LSByZXAoMCwgbmNvbChzdWJncm91cF9zdW1tYXJ5X3BhZykgLSAxKQpkYXRhX2Zvcl9yYWRhciA8LSByYmluZChtYXhfdmFsdWVzLCBtaW5fdmFsdWVzLCBzdWJncm91cF9zdW1tYXJ5X3BhZ1ssIC0xXSkKCiMgQWRkIHJvdyBuYW1lcyBmb3IgY2xhcml0eSAob3B0aW9uYWwpCnJvd25hbWVzKGRhdGFfZm9yX3JhZGFyKSA8LSBjKCJNYXgiLCAiTWluIiwgcGFzdGUoc3ViZ3JvdXBfc3VtbWFyeV9wYWckbGFiZWwpKQoKZGF0YV9mb3JfcmFkYXIgPC0gZGF0YV9mb3JfcmFkYXIgJT4lCiAgcmVuYW1lKFJlcGV0aXRpb24gPSBtZWFuX3JlcGV0aXRpb24sCiAgICAgICAgIFRpbWJyZSA9IG1lYW5fdGltYnJlLAogICAgICAgICBJbnN0cnVtZW50YWwgPSBtZWFuX2luc3RydW1lbnRhbCwKICAgICAgICAgSW50ZW50aW9uYWxpdHkgPSBtZWFuX2ludGVudGlvbmFsaXR5LAogICAgICAgICBDb21wbGV4aXR5ID0gbWVhbl9jb21wbGV4aXR5LAogICAgICAgICBNZWxvZHkgPSBtZWFuX21lbG9keSwKICAgICAgICAgSGFybW9ueSA9IG1lYW5faGFybW9ueSwKICAgICAgICAgUmh5dGhtID0gbWVhbl9yaHl0aG0sCiAgICAgICAgIFB1bHNlID0gbWVhbl9wdWxzZSwKICAgICAgICAgVGVtcG8gPSBtZWFuX3RlbXBvKQoKCgojIENyZWF0ZSB0aGUgcmFkYXIgY2hhcnQKcmFkYXJjaGFydChkYXRhX2Zvcl9yYWRhciwgCiAgICAgICAgICAgYXhpc3R5cGUgPSAxLAogICAgICAgICAgICMgQ3VzdG9taXplIHRoZSBhcHBlYXJhbmNlCiAgICAgICAgICAgcGNvbCA9IGMoImJsdWUiLCAicmVkIiwgImdyZWVuIiksICAjIENvbG9ycyBmb3IgZWFjaCBjbHVzdGVyIChub25tdXNpYywgYW1iaWd1b3VzLCBtdXNpYykKICAgICAgICAgICBwbHdkID0gNCwgICMgTGluZSB3aWR0aAogICAgICAgICAgIHBsdHkgPSAxLCAgIyBMaW5lIHR5cGUKICAgICAgICAgICBjZ2xjb2wgPSAiZ3JleSIsICAjIENvbG9yIG9mIHRoZSBncmlkIGxpbmVzCiAgICAgICAgICAgY2dsdHkgPSAxLCAgIyBUeXBlIG9mIHRoZSBncmlkIGxpbmVzCiAgICAgICAgICAgYXhpc2xhYmNvbCA9ICJibGFjayIsICAjIENvbG9yIG9mIHRoZSBheGlzIGxhYmVscwogICAgICAgICAgIGNheGlzbGFiZWxzID0gc2VxKDAsIDEwMCwgYnkgPSAyMCksICAjIEF4aXMgbGFiZWxzIGZyb20gMCB0byAxMDAKICAgICAgICAgICB2bGNleCA9IDEuNSwgICMgVmFyaWFibGUgbGFiZWwgc2l6ZQogICAgICAgICAgIGNhbGNleCA9IDAuOSwgICMgQXhpcyBsYWJlbCBzaXplCiAgICAgICAgICAgbWF4bWluID0gVFJVRSwgICMgRW5zdXJlIG1heCBhbmQgbWluIHZhbHVlcyBhcmUgdXNlZAogICAgICAgICAgIHNlZyA9IDUgICMgRm9yY2UgNSBzZWdtZW50cyAoMCwgMjAsIDQwLCA2MCwgODAsIDEwMCkKKQoKYGBgCgoKTm93LCB0aGUgaWRlYSBpcyB0byB0cnkgYW5kIGlkZW50aWZ5IGRpZmZlcmVudCBwYXJ0aWNpcGFudCBwcm9maWxlcyB0byB1bmRlcklkZW50aWZ5aW5nIHBhcnRpY2lwYW50IGNsYXNzZXMKCmBgYHtyfQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShicm9vbSkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShkcGx5cikpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShnZ2ZvcnRpZnkpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ3QpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoanRvb2xzKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGxjbW0pKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkobG1lNCkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShsbWVyVGVzdCkpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeShsbXRlc3QpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoc3RyaW5ncikpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh2aXJpZGlzKSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHh0YWJsZSkpKQpgYGAKCgoKV2UgY2Fycnkgb3V0IGEgbGF0ZW50IGNsYXNzIGxpbmVhciBtaXhlZCBtb2RlbCB0byBpZGVudGlmeSBkaWZmZXJlbnQgcGFydGljaXBhbnQgcHJvZmlsZXMuIFdlIHRyeSBoYXZpbmcgdXAgdG8gNiBkaWZmZXJlbnQgcHJvZmlsZXMgKFRoaXMgY29kZSB3aWxsIGJlIHRpbWUgY29uc3VtaW5nLCBpdCB0b29rIHVzIGhhbGYgYSBkYXkgdG8gcnVuLikKCk5vdGljZSB0aGF0IHdlIHVzZSAiY2xhc3MiIGFuZCAicHJvZmlsZSIgaW50ZXJjaGFuZ2VhYmx5Li4uCgpgYGB7cn0KCm1fcmFuZG9tIDwtIGhsbWUoCiAgZml4ZWQgPSBtb25yYSB+IGludGVudGlvbmFsaXR5ICsgaW5zdHJ1bWVudGFsICsgY29tcGxleGl0eSArIHJlcGV0aXRpb24gKyBtZWxvZHkgKyBoYXJtb255ICsgcmh5dGhtICsgdGltYnJlICsgdGVtcG8gKyBwdWxzZSwKICByYW5kb20gPSB+IDEsIAogIHN1YmplY3QgPSAnZXhwX3N1YmplY3RfaWQnLCAKICBuZyA9IDEsIAogIGRhdGEgPSByYXRpbmdzCikKCgptXzJjbCA8LSBobG1lKAogIGZpeGVkID0gbW9ucmEgfiBpbnRlbnRpb25hbGl0eSArIGluc3RydW1lbnRhbCArIGNvbXBsZXhpdHkgKyByZXBldGl0aW9uICsgbWVsb2R5ICsgaGFybW9ueSArIHJoeXRobSArIHRpbWJyZSArIHRlbXBvICsgcHVsc2UsCiAgbWl4dHVyZSA9IH4gaW50ZW50aW9uYWxpdHkgKyBpbnN0cnVtZW50YWwgKyBjb21wbGV4aXR5ICsgcmVwZXRpdGlvbiArIG1lbG9keSArIGhhcm1vbnkgKyByaHl0aG0gKyB0aW1icmUgKyB0ZW1wbyArIHB1bHNlLAogIHJhbmRvbSA9IH4gMSwKICBzdWJqZWN0ID0gJ2V4cF9zdWJqZWN0X2lkJywKICBuZyA9IDIsCiAgQiA9IG1fcmFuZG9tLCAgIyBVc2UgbV9yYW5kb20gYXMgaW5pdGlhbCB2YWx1ZXMKICBkYXRhID0gcmF0aW5ncwopCgoKbV8zY2wgPC0gaGxtZSgKICBmaXhlZCA9IG1vbnJhIH4gaW50ZW50aW9uYWxpdHkgKyBpbnN0cnVtZW50YWwgKyBjb21wbGV4aXR5ICsgcmVwZXRpdGlvbiArIG1lbG9keSArIGhhcm1vbnkgKyByaHl0aG0gKyB0aW1icmUgKyB0ZW1wbyArIHB1bHNlLAogIG1peHR1cmUgPSB+IGludGVudGlvbmFsaXR5ICsgaW5zdHJ1bWVudGFsICsgY29tcGxleGl0eSArIHJlcGV0aXRpb24gKyBtZWxvZHkgKyBoYXJtb255ICsgcmh5dGhtICsgdGltYnJlICsgdGVtcG8gKyBwdWxzZSwKICByYW5kb20gPSB+IDEsCiAgc3ViamVjdCA9ICdleHBfc3ViamVjdF9pZCcsCiAgbmcgPSAzLAogIEIgPSBtX3JhbmRvbSwgICMgVXNlIG1fcmFuZG9tIGFzIGluaXRpYWwgdmFsdWVzCiAgZGF0YSA9IHJhdGluZ3MKKQoKbV80Y2wgPC0gaGxtZSgKICBmaXhlZCA9IG1vbnJhIH4gaW50ZW50aW9uYWxpdHkgKyBpbnN0cnVtZW50YWwgKyBjb21wbGV4aXR5ICsgcmVwZXRpdGlvbiArIG1lbG9keSArIGhhcm1vbnkgKyByaHl0aG0gKyB0aW1icmUgKyB0ZW1wbyArIHB1bHNlLAogIG1peHR1cmUgPSB+IGludGVudGlvbmFsaXR5ICsgaW5zdHJ1bWVudGFsICsgY29tcGxleGl0eSArIHJlcGV0aXRpb24gKyBtZWxvZHkgKyBoYXJtb255ICsgcmh5dGhtICsgdGltYnJlICsgdGVtcG8gKyBwdWxzZSwKICByYW5kb20gPSB+IDEsCiAgc3ViamVjdCA9ICdleHBfc3ViamVjdF9pZCcsCiAgbmcgPSA0LAogIEIgPSBtX3JhbmRvbSwgICMgVXNlIG1fcmFuZG9tIGFzIGluaXRpYWwgdmFsdWVzCiAgZGF0YSA9IHJhdGluZ3MKKQoKCm1fNWNsIDwtIGhsbWUoCiAgZml4ZWQgPSBtb25yYSB+IGludGVudGlvbmFsaXR5ICsgaW5zdHJ1bWVudGFsICsgY29tcGxleGl0eSArIHJlcGV0aXRpb24gKyBtZWxvZHkgKyBoYXJtb255ICsgcmh5dGhtICsgdGltYnJlICsgdGVtcG8gKyBwdWxzZSwKICBtaXh0dXJlID0gfiBpbnRlbnRpb25hbGl0eSArIGluc3RydW1lbnRhbCArIGNvbXBsZXhpdHkgKyByZXBldGl0aW9uICsgbWVsb2R5ICsgaGFybW9ueSArIHJoeXRobSArIHRpbWJyZSArIHRlbXBvICsgcHVsc2UsCiAgcmFuZG9tID0gfiAxLAogIHN1YmplY3QgPSAnZXhwX3N1YmplY3RfaWQnLAogIG5nID0gNSwKICBCID0gbV9yYW5kb20sICAjIFVzZSBtX3JhbmRvbSBhcyBpbml0aWFsIHZhbHVlcwogIGRhdGEgPSByYXRpbmdzCikKCgptXzZjbCA8LSBobG1lKAogIGZpeGVkID0gbW9ucmEgfiBpbnRlbnRpb25hbGl0eSArIGluc3RydW1lbnRhbCArIGNvbXBsZXhpdHkgKyByZXBldGl0aW9uICsgbWVsb2R5ICsgaGFybW9ueSArIHJoeXRobSArIHRpbWJyZSArIHRlbXBvICsgcHVsc2UsCiAgbWl4dHVyZSA9IH4gaW50ZW50aW9uYWxpdHkgKyBpbnN0cnVtZW50YWwgKyBjb21wbGV4aXR5ICsgcmVwZXRpdGlvbiArIG1lbG9keSArIGhhcm1vbnkgKyByaHl0aG0gKyB0aW1icmUgKyB0ZW1wbyArIHB1bHNlLAogIHJhbmRvbSA9IH4gMSwKICBzdWJqZWN0ID0gJ2V4cF9zdWJqZWN0X2lkJywKICBuZyA9IDYsCiAgQiA9IG1fcmFuZG9tLCAgIyBVc2UgbV9yYW5kb20gYXMgaW5pdGlhbCB2YWx1ZXMKICBkYXRhID0gcmF0aW5ncwopCgoKCmQ8LXN1bW1hcnl0YWJsZShtX3JhbmRvbSwgbV8yY2wsIG1fM2NsLCBtXzRjbCwgbV81Y2wsIG1fNmNsLAogICAgICAgICAgICAgICAgIHdoaWNoID0gYygiRyIsICJsb2dsaWsiLCAibnBtIiwgIkJJQyIsICIlY2xhc3MiLCAiZW50cm9weSIpKSAjPz8/IGNsYXNzZXMgaXMgYmV0dGVyCgpkPC0gYXMuZGF0YS5mcmFtZShkKQojdmlldyhkKQoKc3VtbWFyeShtX3JhbmRvbSkKc3VtbWFyeShtXzJjbCkKc3VtbWFyeShtXzNjbCkKc3VtbWFyeShtXzRjbCkKc3VtbWFyeShtXzVjbCkKc3VtbWFyeShtXzZjbCkKCmxvZ0xpa18yY2wgPC0gbV8yY2wkbG9nbGlrCmxvZ0xpa18zY2wgPC0gbV8zY2wkbG9nbGlrCmxvZ0xpa180Y2wgPC0gbV80Y2wkbG9nbGlrCmxvZ0xpa181Y2wgPC0gbV81Y2wkbG9nbGlrCmxvZ0xpa182Y2wgPC0gbV82Y2wkbG9nbGlrCgpgYGAKCgpTZWxlY3Rpb24gb2YgdGhlIG51bWJlciBvZiBjbGFzc2VzOiA3IGNyaXRlcmlhIChzZWUgPGh0dHBzOi8vd3d3LmRpc3BsYXlyLmNvbS93b3JrLW51bWJlci1jbGFzc2VzLWxhdGVudC1jbGFzcy1hbmFseXNpcy8jPjpcfjp0ZXh0PVRoZXJlJTIwYXJlJTIwc2V2ZW4lMjBhcHByb2FjaGVzJTIwdG8seW91ciUyMG93biUyMExhdGVudCUyMENsYXNzJTIwQW5hbHlzaXMhKQoKV2Ugd2lsbCBsb29rIGF0IHRoZSBCSUMgYW5kIHRoZSAibm8gc21hbGwgY2xhc3NlcyIgY3JpdGVyaWEKCk5vIHNtYWxsIGNsYXNzZXM6IFRoZSBiYXNpYyBpZGVhIG9mIHRoaXMgYXBwcm9hY2ggaXMgdGhhdCB5b3UgY2hvb3NlIHRoZSBoaWdoZXN0IG51bWJlciBvZiBjbGFzc2VzLCBzdWNoIHRoYXQgbm9uZSBvZiB0aGUgY2xhc3NlcyBhcmUgc21hbGwgKGUuZy4sIGxlc3MgdGhhbiA1JSBvZiB0aGUgc2FtcGxlKS4gVGhpcyBydWxlIGhhcyBsb25nIGJlZW4gdXNlZCBpbiBwcmFjdGljZSBhcyBhIHBhcnQgb2YgdGhlIGlkZWEgb2YgZG9tYWluLXVzZWZ1bG5lc3MgYnV0IGhhcyByZWNlbnRseSBiZWVuIGRpc2NvdmVyZWQgYWxzbyB0byBoYXZlIHNvbWUgdGhlb3JldGljYWwganVzdGlmaWNhdGlvbiAoTmFzc2VyaW5lamFkLCBLLiwgdmFuIFJvc21hbGVuLCBKLiwgZGUgS29ydCwgVy4sIExlc2FmZnJlLCBFLiAoMjAxNykgQ29tcGFyaXNvbiBvZiBjcml0ZXJpYSBmb3IgY2hvb3NpbmcgdGhlIG51bWJlciBvZiBjbGFzc2VzIGluIEJheWVzaWFuIGZpbml0ZSBtaXh0dXJlIG1vZGVscy4gUGxvUyBvbmUsIDEyKS4KCkJhc2VkIG9uIHRoZXNlIGNyaXRlcmlhLCBhbmQgdGFibGUgImQiLCB3ZSBwaWNrZWQgdGhlIHNvbHV0aW9uIHdpdGggNSBjbGFzc2VzLgoKYGBge3J9CnBvc3Rwcm9iKG1fMmNsKSAKcG9zdHByb2IobV8zY2wpIApwb3N0cHJvYihtXzRjbCkgCnBvc3Rwcm9iKG1fNWNsKSAKcG9zdHByb2IobV82Y2wpIAoKc3VtbWFyeShtXzVjbCkKCgpwZW9wbGVfMl9jbGFzc2VzIDwtIGFzLmRhdGEuZnJhbWUobV8yY2wkcHByb2IpCnBlb3BsZV8zX2NsYXNzZXMgPC0gYXMuZGF0YS5mcmFtZShtXzNjbCRwcHJvYikKcGVvcGxlXzRfY2xhc3NlcyA8LSBhcy5kYXRhLmZyYW1lKG1fNGNsJHBwcm9iKQpwZW9wbGVfNV9jbGFzc2VzIDwtIGFzLmRhdGEuZnJhbWUobV81Y2wkcHByb2IpCnBlb3BsZV82X2NsYXNzZXMgPC0gYXMuZGF0YS5mcmFtZShtXzZjbCRwcHJvYikKIyBWaWV3KHBlb3BsZV81X2NsYXNzZXMpCgoKcGVvcGxlXzJfY2xhc3NlcyR0d29jbGFzc2VzIDwtIHBlb3BsZV8yX2NsYXNzZXMkY2xhc3MKcGVvcGxlXzNfY2xhc3NlcyR0aHJlZWNsYXNzZXMgPC0gcGVvcGxlXzNfY2xhc3NlcyRjbGFzcwpwZW9wbGVfNF9jbGFzc2VzJGZvdXJjbGFzc2VzIDwtIHBlb3BsZV80X2NsYXNzZXMkY2xhc3MKcGVvcGxlXzZfY2xhc3NlcyRzaXhjbGFzc2VzIDwtIHBlb3BsZV82X2NsYXNzZXMkY2xhc3MKCgpgYGAKCgpIZXJlLCBJIGFkZCB0aGUgNS1jbGFzcy1zb2x1dGlvbiBpbiB0aGUgcmF0aW5ncyBERi4gCgpgYGB7cn0KCnN0cihwZW9wbGUpCgojQ2xhc3MgaXMgdGhlIHNvbHV0aW9uIHdlIHBpY2tlZCwgaXQgaW5jbHVkZXMgNSBjbGFzc2VzLCBudW1iZXJzIGZyb20gMSB0byA1IHNob3dzIHdoaWNoIGNsYXNzIGEgcGFydGljaXBhbnRzIGhhcyBiZWVuIGFzc2lnbmVkLiAKCnJhdGluZ3NfY2xhc3MgPC0gcmF0aW5ncyAlPiUKICBsZWZ0X2pvaW4ocGVvcGxlXzVfY2xhc3NlcyAlPiUKICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGV4cF9zdWJqZWN0X2lkLCBjbGFzcyksCiAgICAgICAgICAgIGJ5ID0gImV4cF9zdWJqZWN0X2lkIikKCgpgYGAKClRoZSBtZWFuIHJhdGluZ3Mgb2YgZmVhdHVyZXMgZm9yIGVhY2ggb2YgdGhlIDUgcHJvZmlsZXMuIAoKYGBge3J9CgpjbHVzdGVyX21lYW5zIDwtIGFnZ3JlZ2F0ZSgKICAuIH4gY2xhc3MsIAogIGRhdGEgPSByYXRpbmdzX2NsYXNzWywgYygiY2xhc3MiLCAiaW50ZW50aW9uYWxpdHkiLCAiaW5zdHJ1bWVudGFsIiwgImNvbXBsZXhpdHkiLCAicmVwZXRpdGlvbiIsICJtZWxvZHkiLCAiaGFybW9ueSIsICJyaHl0aG0iLCAidGltYnJlIiwgInRlbXBvIiwgInB1bHNlIildLCAKICBtZWFuCikKCmNsdXN0ZXJfc2QgPC0gYWdncmVnYXRlKAogIC4gfiBjbGFzcywgCiAgZGF0YSA9IHJhdGluZ3NfY2xhc3NbLCBjKCJjbGFzcyIsICJpbnRlbnRpb25hbGl0eSIsImluc3RydW1lbnRhbCIsICJjb21wbGV4aXR5IiwgInJlcGV0aXRpb24iLCAibWVsb2R5IiwgImhhcm1vbnkiLCAicmh5dGhtIiwgInRpbWJyZSIsICJ0ZW1wbyIsICJwdWxzZSIpXSwgCiAgc2QKKQoKcHJpbnQoY2x1c3Rlcl9tZWFucykKcHJpbnQoY2x1c3Rlcl9zZCkKCgpgYGAKCgpOb3cgd2UgY2FycnkgTE1NcyBmb3IgZWFjaCBwcm9maWxlLiBDYXV0aW9uLCB0aGF0IHdlIGhhdmUgbGVzcyBwYXJ0aWNpcGFudHMgaW4gZWFjaCBtb2RlbCwgaW5jcmVhc2luZyB0aGUgcG9zc2liaWxpdHkgZm9yIG11bHRpY29sbGluYXJpdHkgYW5kIG90aGVyIGlzc3Vlcy4uLiAKCmBgYHtyfQojIzEgQ0xBU1MKCmNsYXNzMV9tb2RlbHMgPC0gcmF0aW5nc19jbGFzcyAlPiUKICBmaWx0ZXIoY2xhc3MgPT0gIjEiKSAlPiUKICBsbWVyKG1vbnJhIH4gaW50ZW50aW9uYWxpdHkgKyBpbnN0cnVtZW50YWwgKyBjb21wbGV4aXR5ICsgcmVwZXRpdGlvbiArIG1lbG9keSArIGhhcm1vbnkgKyByaHl0aG0gKyB0aW1icmUgKyB0ZW1wbyArIHB1bHNlICsgKDEgfCBleHBfc3ViamVjdF9pZCkgKyAoMSB8IGF1ZGlvX25hbWUpLCBkYXRhID0gLikKCnN1bW1hcnkoY2xhc3MxX21vZGVscykKci5zcXVhcmVkR0xNTShjbGFzczFfbW9kZWxzKQpjYXI6OnZpZihjbGFzczFfbW9kZWxzKSAKcmFuZChjbGFzczFfbW9kZWxzKQpwZXJmb3JtYW5jZTo6aWNjKGNsYXNzMV9tb2RlbCwgYnlfZ3JvdXAgPSBUUlVFKQoKCgpjbGFzczJfbW9kZWxzIDwtIHJhdGluZ3NfY2xhc3MgJT4lCiAgZmlsdGVyKGNsYXNzID09ICIyIikgJT4lCiAgbG1lcihtb25yYSB+IGludGVudGlvbmFsaXR5ICsgaW5zdHJ1bWVudGFsICsgY29tcGxleGl0eSArIHJlcGV0aXRpb24gKyBtZWxvZHkgKyBoYXJtb255ICsgcmh5dGhtICsgdGltYnJlICsgdGVtcG8gKyBwdWxzZSArICgxIHwgZXhwX3N1YmplY3RfaWQpICsgKDEgfCBhdWRpb19uYW1lKSwgZGF0YSA9IC4pCgpzdW1tYXJ5KGNsYXNzMl9tb2RlbHMpCnIuc3F1YXJlZEdMTU0oY2xhc3MyX21vZGVscykKY2FyOjp2aWYoY2xhc3MyX21vZGVscykgCnJhbmQoY2xhc3MyX21vZGVscykKcGVyZm9ybWFuY2U6OmljYyhjbGFzczJfbW9kZWxzLCBieV9ncm91cCA9IFRSVUUpCgoKCmNsYXNzM19tb2RlbHMgPC0gcmF0aW5nc19jbGFzcyAlPiUKICBmaWx0ZXIoY2xhc3MgPT0gIjMiKSAlPiUKICBsbWVyKG1vbnJhIH4gaW50ZW50aW9uYWxpdHkgKyBpbnN0cnVtZW50YWwgKyBjb21wbGV4aXR5ICsgcmVwZXRpdGlvbiArIG1lbG9keSArIGhhcm1vbnkgKyByaHl0aG0gKyB0aW1icmUgKyB0ZW1wbyArIHB1bHNlICsgKDEgfCBleHBfc3ViamVjdF9pZCkgKyAoMSB8IGF1ZGlvX25hbWUpLCBkYXRhID0gLikKCnN1bW1hcnkoY2xhc3MzX21vZGVscykKci5zcXVhcmVkR0xNTShjbGFzczNfbW9kZWxzKQpjYXI6OnZpZihjbGFzczNfbW9kZWwpIApyYW5kKGNsYXNzM19tb2RlbCkKcGVyZm9ybWFuY2U6OmljYyhjbGFzczNfbW9kZWwsIGJ5X2dyb3VwID0gVFJVRSkKCgpjbGFzczRfbW9kZWxzIDwtIHJhdGluZ3NfY2xhc3MgJT4lCiAgZmlsdGVyKGNsYXNzID09ICI0IikgJT4lCiAgbG1lcihtb25yYSB+IGludGVudGlvbmFsaXR5ICsgaW5zdHJ1bWVudGFsICsgY29tcGxleGl0eSArIHJlcGV0aXRpb24gKyBtZWxvZHkgKyBoYXJtb255ICsgcmh5dGhtICsgdGltYnJlICsgdGVtcG8gKyBwdWxzZSArICgxIHwgZXhwX3N1YmplY3RfaWQpICsgKDEgfCBhdWRpb19uYW1lKSwgZGF0YSA9IC4pCgpzdW1tYXJ5KGNsYXNzNF9tb2RlbHMpCnIuc3F1YXJlZEdMTU0oY2xhc3M0X21vZGVscykKY2FyOjp2aWYoY2xhc3M0X21vZGVsKSAKcmFuZChjbGFzczRfbW9kZWwpCnBlcmZvcm1hbmNlOjppY2MoY2xhc3M0X21vZGVsLCBieV9ncm91cCA9IFRSVUUpCgpjbGFzczVfbW9kZWxzIDwtIHJhdGluZ3NfY2xhc3MgJT4lCiAgZmlsdGVyKGNsYXNzID09ICI1IikgJT4lCiAgbG1lcihtb25yYSB+IGludGVudGlvbmFsaXR5ICsgaW5zdHJ1bWVudGFsICsgY29tcGxleGl0eSArIHJlcGV0aXRpb24gKyBtZWxvZHkgKyBoYXJtb255ICsgcmh5dGhtICsgdGltYnJlICsgdGVtcG8gKyBwdWxzZSArICgxIHwgZXhwX3N1YmplY3RfaWQpICsgKDEgfCBhdWRpb19uYW1lKSwgZGF0YSA9IC4pCgpzdW1tYXJ5KGNsYXNzNV9tb2RlbHMpCnIuc3F1YXJlZEdMTU0oY2xhc3M1X21vZGVscykKY2FyOjp2aWYoY2xhc3M1X21vZGVsKSAKcmFuZChjbGFzczVfbW9kZWwpCnBlcmZvcm1hbmNlOjppY2MoY2xhc3M1X21vZGVsLCBieV9ncm91cCA9IFRSVUUpCmBgYAoKUmVwb3J0ZWQgZmlndXJlIGluIHRoZSBwYXBlcgoKYGBge3J9CiMgR2VuZXJhdGUgVmlyaWRpcyBjb2xvciBwYWxldHRlIHdpdGggNSBkaXN0aW5jdCBjb2xvcnMKdmlyaWRpc19jb2xvcnMgPC0gdmlyaWRpc19wYWwob3B0aW9uID0gIkQiKSg1KQoKcGxvdF9zdW1tcyhjbGFzczFfbW9kZWxzLCBjbGFzczJfbW9kZWxzLCBjbGFzczNfbW9kZWxzLCBjbGFzczRfbW9kZWxzLCBjbGFzczVfbW9kZWxzLCAKICAgICAgICAgICBzY2FsZSA9IEZBTFNFLCAKICAgICAgICAgICBjb2xvcnMgPSB2aXJpZGlzX2NvbG9ycywKICAgICAgICAgICBtb2RlbC5uYW1lcyA9IGMoIkNsYXNzIDEiLCAiQ2xhc3MgMiIsICJDbGFzcyAzIiwgIkNsYXNzIDQiLCAiQ2xhc3MgNSIpKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKyAgCiAgdGhlbWUoCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI1KSwgICAgICAKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksICAgIAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAgIyBBZGp1c3QgbGVnZW5kIHRpdGxlIHNpemUKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpCiAgKSArCiAgbGFicyhjb2xvciA9ICJDbGFzcyIpICAjIFJlbmFtZSB0aGUgbGVnZW5kIHRpdGxlCgoKYGBgCgpQYXJ0aWNpcGFudCBjaGFyYWN0ZXJpc3RpY3MgYW5kIGNsYXNzZXMuLi4gV2UgY2hlY2sgaWYgcGFydGljaXBhbnRzIGluIHRoZXNlIGRpZmZlcmVudCBwcm9maWxlcyBkaWZmZXIgcmVnYXJkaW5nIGFnZSwgYXVkaXRvcnkgaW1hZ2VyeSwgbXVzaWNhbCBzb3BoaXN0aWNhdGlvbiwgb3Igb3Blbm5lc3MgdG8gZXhwZXJpZW5jZS4uLgoKYGBge3J9CgptZWFuc19zY2FsZXNfYWdlX2NsYXNzIDwtIG1lYW5zX3NjYWxlc19hZ2UgJT4lCiAgbGVmdF9qb2luKHBlb3BsZV81X2NsYXNzZXMgJT4lCiAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChleHBfc3ViamVjdF9pZCwgY2xhc3MpLAogICAgICAgICAgICBieSA9ICJleHBfc3ViamVjdF9pZCIpCgpzdHIobWVhbnNfc2NhbGVzX2FnZV9nZW5yZXMpCgojIEFOT1ZBIGZvciAnYmFpcycKYW5vdmFfYmFpcyA8LSBhb3YoYmFpcyB+IGZhY3RvcihjbGFzcyksIGRhdGEgPSBtZWFuc19zY2FsZXNfYWdlX2NsYXNzKQpzdW1tYXJ5KGFub3ZhX2JhaXMpCgojIEFOT1ZBIGZvciAnZ29sZCcKYW5vdmFfZ29sZCA8LSBhb3YoZ29sZCB+IGZhY3RvcihjbGFzcyksIGRhdGEgPSBtZWFuc19zY2FsZXNfYWdlX2NsYXNzKQpzdW1tYXJ5KGFub3ZhX2dvbGQpCgojIEFOT1ZBIGZvciAndG90YWxfb3Blbm5lc3MnCmFub3ZhX29wZW5uZXNzIDwtIGFvdih0b3RhbF9vcGVubmVzcyB+IGZhY3RvcihjbGFzcyksIGRhdGEgPSBtZWFuc19zY2FsZXNfYWdlX2NsYXNzKQpzdW1tYXJ5KGFub3ZhX29wZW5uZXNzKQoKIyBBTk9WQSBmb3IgJ2FnZScKYW5vdmFfYWdlIDwtIGFvdihhZ2UgfiBmYWN0b3IoY2xhc3MpLCBkYXRhID0gbWVhbnNfc2NhbGVzX2FnZV9jbGFzcykKc3VtbWFyeShhbm92YV9hZ2UpCgpgYGAKClRoZXkgZG9uJ3QuCgpSZXBvcnRlZCBmaWd1cmUgb2YgYWdlLCBCQUlTLVYsIEdvbGQtTVNJIGFuZCBPcGVubmVzcyBzY29yZXMgb2YgYWxsIDUgY2xhc3NlcwoKYGBge3J9CgptZWFuc19zY2FsZXNfYWdlX2NsYXNzJGNsYXNzIDwtIGFzLmZhY3RvcihtZWFuc19zY2FsZXNfYWdlX2NsYXNzJGNsYXNzKQoKZ2dwbG90KG1lYW5zX3NjYWxlc19hZ2VfY2xhc3MsIGFlcyh4ID0gY2xhc3MsIHkgPSBhZ2UsIGNvbG9yID0gY2xhc3MsIGZpbGwgPSBjbGFzcykpICsKICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjc1KSkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC4wNSwgc2l6ZSA9IDEpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSArICAKICBsYWJzKHggPSAiQ2xhc3MiLCB5ID0gIkFnZSIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICsgICAKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE2KSArIAogIHRoZW1lKAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2UgPSAiYm9sZCIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAgCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksICAKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksICAKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpIAogICkgKwogIGdncGxvdChtZWFuc19zY2FsZXNfYWdlX2NsYXNzLCBhZXMoeCA9IGNsYXNzLCB5ID0gYmFpcywgY29sb3IgPSBjbGFzcywgZmlsbCA9IGNsYXNzKSkgKwogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzUpKSArCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjA1LCBzaXplID0gMSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsgIAogIGxhYnMoeCA9ICJDbGFzcyIsIHkgPSAiQkFJUy1WIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKyAgIAogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTYpICsgCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICJib2xkIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsICAKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwgIAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgIAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkgCiAgKSArCiAgZ2dwbG90KG1lYW5zX3NjYWxlc19hZ2VfY2xhc3MsIGFlcyh4ID0gY2xhc3MsIHkgPSBnb2xkLCBjb2xvciA9IGNsYXNzLCBmaWxsID0gY2xhc3MpKSArCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC41LCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43NSkpICsKICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuMDUsIHNpemUgPSAxKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKyAgCiAgbGFicyh4ID0gIkNsYXNzIiwgeSA9ICJHb2xkLU1TSSIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICsgICAKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE2KSArIAogIHRoZW1lKAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMzApLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2UgPSAiYm9sZCIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAgCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksICAKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksICAKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpIAogICkgKwogIGdncGxvdChtZWFuc19zY2FsZXNfYWdlX2NsYXNzLCBhZXMoeCA9IGNsYXNzLCB5ID0gdG90YWxfb3Blbm5lc3MsIGNvbG9yID0gY2xhc3MsIGZpbGwgPSBjbGFzcykpICsKICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjc1KSkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC4wNSwgc2l6ZSA9IDEpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSArICAKICBsYWJzKHggPSAiQ2xhc3MiLCB5ID0gIk9wZW5uZXNzIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKyAgIAogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTYpICsgCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAzMCksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICJib2xkIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsICAKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwgIAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgIAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkgCiAgKSAKICAKCmBgYAoKCkxldCdzIHN1bW1hcml6ZSB0aGUgZmluZGluZ3MgaW4gYSB0YWJsZSEKCmBgYHtyfQoKIyBDcmVhdGUgYSBsaXN0IG9mIHlvdXIgbW9kZWxzCm1vZGVscyA8LSBsaXN0KGNsYXNzMSA9IGNsYXNzMV9tb2RlbHMsIAogICAgICAgICAgICAgICBjbGFzczIgPSBjbGFzczJfbW9kZWxzLCBjbGFzczMgPSBjbGFzczNfbW9kZWxzLCAKICAgICAgICAgICAgICAgY2xhc3M0ID0gY2xhc3M0X21vZGVscywgY2xhc3M1ID0gY2xhc3M1X21vZGVscykKCmZpeGVkX2VmZmVjdHNfbGlzdCA8LSBwdXJycjo6bWFwKG1vZGVscywgfiBicm9vbTo6dGlkeSgueCwgZWZmZWN0cyA9ICJmaXhlZCIpKQoKIyBDb21iaW5lIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZQpmaXhlZF9lZmZlY3RzIDwtIGJpbmRfcm93cyhmaXhlZF9lZmZlY3RzX2xpc3QsIC5pZCA9ICJjbGFzcyIpCgpmaXhlZF9lZmZlY3RzIDwtIGZpeGVkX2VmZmVjdHMgJT4lCiAgbXV0YXRlKHNpZ25pZmljYW5jZSA9IGNhc2Vfd2hlbigKICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgcC52YWx1ZSA8IDAuMDEgIH4gIioqIiwKICAgIHAudmFsdWUgPCAwLjA1ICB+ICIqIiwKICAgIFRSVUUgICAgICAgICAgICB+ICJucyIKICApKQoKIyBDYWxjdWxhdGUgUl4yIGZvciBlYWNoIG1vZGVsIGFuZCBpbmNsdWRlIGNsYXNzCnJzcXVhcmVkX3ZhbHVlcyA8LSBwdXJycjo6aW1hcChtb2RlbHMsIH4gewogIHIyIDwtIHIuc3F1YXJlZEdMTU0oLngpICAjIENhbGN1bGF0ZSBSMgogIHRpYmJsZSgKICAgIGNsYXNzID0gLnksICAgICAgICAgICAgIyBBZGQgY2xhc3MgbmFtZSAobW9kZWwgbmFtZSBvciBpZGVudGlmaWVyKQogICAgUjJtID0gcjJbMV0sICAgICAgICAgICAjIE1hcmdpbmFsIFIyCiAgICBSMmMgPSByMlsyXSAgICAgICAgICAgICMgQ29uZGl0aW9uYWwgUjIKICApCn0pICU+JSBiaW5kX3Jvd3MoKSAgIyBDb21iaW5lIHRoZSBsaXN0IG9mIHRpYmJsZXMgaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lCgojIFByaW50IHRoZSByZXN1bHRpbmcgZGF0YSBmcmFtZQpwcmludChyc3F1YXJlZF92YWx1ZXMpCgoKcHJpbnQocnNxdWFyZWRfdmFsdWVzKQoKIyBSZXNoYXBlIHRvIG1ha2UgZmVhdHVyZXMgKHRlcm1zKSByb3dzIGFuZCBjbGFzc2VzIGNvbHVtbnMKc2lnbmlmaWNhbmNlX3RhYmxlIDwtIGZpeGVkX2VmZmVjdHMgJT4lCiAgZHBseXI6OnNlbGVjdChjbGFzcywgdGVybSwgc2lnbmlmaWNhbmNlKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY2xhc3MsIHZhbHVlc19mcm9tID0gc2lnbmlmaWNhbmNlLCB2YWx1ZXNfZmlsbCA9ICJucyIpCgpyc3F1YXJlZF9yb3dzIDwtIHJzcXVhcmVkX3ZhbHVlcyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCJSIiksIG5hbWVzX3RvID0gInRlcm0iLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUodGVybSA9IGNhc2Vfd2hlbigKICAgIHRlcm0gPT0gIlIybSIgfiAiTWFyZ2luYWwgUsKyIiwKICAgIHRlcm0gPT0gIlIyYyIgfiAiQ29uZGl0aW9uYWwgUsKyIgogICkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjbGFzcywgdmFsdWVzX2Zyb20gPSB2YWx1ZSwgbmFtZXNfcHJlZml4ID0gImNsYXNzIikgJT4lCiAgbXV0YXRlKGFjcm9zcygtdGVybSwgYXMuY2hhcmFjdGVyKSkgICMgRW5zdXJlIGNvbXBhdGliaWxpdHkgd2l0aCBgc2lnbmlmaWNhbmNlCgpyc3F1YXJlZF9yb3dzIDwtIHJzcXVhcmVkX3Jvd3MgJT4lCiAgbXV0YXRlKGFjcm9zcyhzdGFydHNfd2l0aCgiY2xhc3MiKSwgfiBhcy5jaGFyYWN0ZXIoLikpKQoKcnNxdWFyZWRfcm93c19jbGVhbiA8LSByc3F1YXJlZF9yb3dzICU+JQogIHJlbmFtZV93aXRoKH4gc3ViKCJeY2xhc3MiLCAiIiwgLiksIHN0YXJ0c193aXRoKCJjbGFzcyIpKQoKIyBUaGVuIHlvdSBjYW4gY29udGludWUgeW91ciBwaXBlbGluZSB3aXRoIHRoZSBjbGVhbmVkIGRhdGEKY29tYmluZWRfdGFibGUgPC0gYmluZF9yb3dzKHNpZ25pZmljYW5jZV90YWJsZSwgcnNxdWFyZWRfcm93c19jbGVhbikKCnBhcnRpY2lwYW50X2NvdW50cyA8LSB0aWJibGUoCiAgdGVybSAgPSAiIyBvZiBQYXJ0aWNpcGFudHMiLAogIGNsYXNzMSA9ICIxNyIsIAogIGNsYXNzMiA9ICIxNCIsIAogIGNsYXNzMyA9ICIyMSIsIAogIGNsYXNzNCA9ICIzNSIsIAogIGNsYXNzNSA9ICIxMSIKKQoKIyBBcHBlbmQgdGhlIHBhcnRpY2lwYW50IGNvdW50cyB0byB5b3VyIG9yaWdpbmFsIHRhYmxlCmZpbmFsX3RhYmxlIDwtIGJpbmRfcm93cyhjb21iaW5lZF90YWJsZSwgcGFydGljaXBhbnRfY291bnRzKQoKIyBQcmludCB0aGUgdXBkYXRlZCB0YWJsZQpwcmludChmaW5hbF90YWJsZSkKCgpmaW5hbF90YWJsZSAlPiUKICBtdXRhdGUoYWNyb3NzKAogICAgc3RhcnRzX3dpdGgoImNsYXNzIiksCiAgICB+IGlmZWxzZSh0ZXJtICVpbiUgYygiTWFyZ2luYWwgUsKyIiwgIkNvbmRpdGlvbmFsIFLCsiIsICIjIG9mIFBhcnRpY2lwYW50cyIpLCAuLCBzdHJfc3ViKC4sIDEsIDQpKQogICkpICU+JQogIG11dGF0ZShhY3Jvc3MoCiAgICBzdGFydHNfd2l0aCgiY2xhc3MiKSwKICAgIH4gaWZlbHNlKHRlcm0gJWluJSBjKCJNYXJnaW5hbCBSwrIiLCAiQ29uZGl0aW9uYWwgUsKyIiksIGFzLm51bWVyaWMoLiksIC4pCiAgKSkgJT4lCiAgZ3QoKSAlPiUKICB0YWJfaGVhZGVyKAogICAgdGl0bGUgPSAiU2lnbmlmaWNhbmNlIG9mIFByZWRpY3RvcnMgYW5kIFLCsiBWYWx1ZXMgQWNyb3NzIENsYXNzZXMiLAogICAgc3VidGl0bGUgPSAiU2lnbmlmaWNhbmNlIGxldmVsczogKioqICg8MC4wMDEpLCAqKiAoPDAuMDEpLCAqICg8MC4wNSksIG5zIChub3Qgc2lnbmlmaWNhbnQpIgogICkgJT4lCiAgZGF0YV9jb2xvcigKICAgIGNvbHVtbnMgPSBzdGFydHNfd2l0aCgiY2xhc3MiKSwKICAgIGNvbG9ycyA9IHNjYWxlczo6Y29sX2ZhY3RvcigKICAgICAgcGFsZXR0ZSA9IGMoInllbGxvdyIsICJvcmFuZ2UiLCAicmVkIiwgIndoaXRlIiksCiAgICAgIGRvbWFpbiA9IGMoIioqKiIsICIqKiIsICIqIiwgIm5zIikKICAgICkKICApICU+JQogIGZtdF9udW1iZXIoCiAgICByb3dzID0gdGVybSAlaW4lIGMoIk1hcmdpbmFsIFLCsiIsICJDb25kaXRpb25hbCBSwrIiKSwKICAgIGRlY2ltYWxzID0gMwogICkgJT4lCiAgdGFiX3N0eWxlKAogICAgc3R5bGUgPSBjZWxsX2ZpbGwoY29sb3IgPSAid2hpdGUiKSwKICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkocm93cyA9IHRlcm0gJWluJSBjKCJNYXJnaW5hbCBSwrIiLCAiQ29uZGl0aW9uYWwgUsKyIikpCiAgKSAlPiUKICB0YWJfc3R5bGUoCiAgICBzdHlsZSA9IGNlbGxfdGV4dChjb2xvciA9ICJibGFjayIpLAogICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShyb3dzID0gdGVybSAlaW4lIGMoIk1hcmdpbmFsIFLCsiIsICJDb25kaXRpb25hbCBSwrIiLCAiIyBvZiBQYXJ0aWNpcGFudHMiKSkKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF9maWxsKGNvbG9yID0gIndoaXRlIiksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KHJvd3MgPSB0ZXJtICVpbiUgYygiIyBvZiBQYXJ0aWNpcGFudHMiKSkKICApCgpsaWJyYXJ5KHdyaXRleGwpCgojIFNhdmUgdGhlIHVuZGVybHlpbmcgZmluYWxfdGFibGUgdG8gRXhjZWwuIFdlIGVkaXRlZCB0aGUgdGFibGUgZm9ybWF0IGFuZCBoYXZlIHRoYXQgdmVyc2lvbiBpbiB0aGUgcGFwZXIgKGFsc28gd2l0aCByb3VuZGVkIHZhbHVlcykKd3JpdGVfeGxzeChmaW5hbF90YWJsZSwgcGF0aCA9ICJmaW5hbF90YWJsZS54bHN4IikKCmBgYAoKCgoK